应为每个应用创建专用账号并限制权限,禁用root远程登录,收缩监听地址,启用密码策略插件,移除file/super权限,按角色分层授权以平衡安全与运维需求。

root用户不该直接用于应用连接
MySQL 的 root 用户默认拥有所有权限,包括 DROP DATABASE、SHUTDOWN、FILE 等高危操作。生产环境里用 root 跑应用或中间件,等于把数据库的“物理钥匙”交给了业务代码——一旦应用被注入或配置泄露,整个实例可能瞬间清空。
实操建议:
- 为每个应用单独创建专用账号,例如
app_payment,只赋予SELECT、INSERT、UPDATE、DELETE权限,且限定在对应数据库(如payment_db)内 - 禁用
root的远程登录:DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; FLUSH PRIVILEGES;
- 若必须远程管理,改用跳板机 + SSH 隧道,或通过
mysql -h 127.0.0.1 -u root(走 TCP)而非-h localhost(走 socket),再配合防火墙限制源 IP
如何安全地回收 root 的 FILE 和 SUPER 权限
FILE 权限允许读写服务器任意文件(如 SELECT ... INTO OUTFILE 可导出 /etc/passwd),SUPER 则能 kill 线程、修改全局变量、绕过 binlog 控制——这两项是提权和持久化攻击的关键跳板。
MySQL 8.0+ 不支持直接 REVOKE FILE ON *.* FROM 'root'(因为它是超级用户隐式权限),必须从根源限制:
- 启动时加参数
--secure-file-priv=/var/lib/mysql-files/,强制LOAD DATA INFILE只能读该目录下的文件 - 移除
root的SUPER权限需先启用skip-grant-tables模式重置,但更稳妥的做法是:用CREATE USER 'dba_admin'@'localhost' IDENTIFIED BY 'xxx' WITH ADMIN OPTION;创建替代管理员,并确保其不带FILE - 检查残留风险:
SELECT User,Host,File_priv,Super_priv FROM mysql.user WHERE User='root';,输出应为N或NULL
密码策略与认证插件要硬性启用
默认的 mysql_native_password 插件不强制复杂度,且旧版本允许空密码。MySQL 5.7+ 提供 validate_password 插件,但需手动加载并设阈值。
执行顺序不能错:
- 先加载插件:
INSTALL PLUGIN validate_password SONAME 'validate_password.so';
- 再设强度:
SET GLOBAL validate_password.policy = MEDIUM;(要求至少 1 个大写、1 个小写、1 个数字、1 个特殊字符,长度 ≥ 8) - 对
root强制改密:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'NewPass!2024'; - 验证是否生效:
SELECT VALIDATE_PASSWORD_STRENGTH('weak'); → 0,SELECT VALIDATE_PASSWORD_STRENGTH('StrongP@ss2024'); → 100
监听地址和网络层必须收缩
MySQL 默认绑定 0.0.0.0:3306,只要端口开放,就可能被暴力破解或未授权访问。很多运维人员只改了 bind-address 却忘了防火墙同步。
关键动作:
- 配置文件中明确写
bind-address = 127.0.0.1(仅本地),或指定内网 IP(如192.168.10.5),绝不要留空或写* - 操作系统级封堵:
ufw deny 3306(Ubuntu)或firewall-cmd --permanent --remove-port=3306/tcp(CentOS) - 确认无其他监听进程:
netstat -tlnp | grep :3306,输出中的Local Address应为设定 IP,不是*:3306 - 如果用了云服务(如阿里云 RDS),安全组规则比 MySQL 自身配置更优先,务必检查入方向是否只放行 DBA 跳板机 IP
真正难的是权限收敛后的故障定位——比如某个凌晨三点的慢查询突然卡住,而你又没留 PROCESS 权限给监控账号,这时候连 SHOW PROCESSLIST 都看不到。所以最小权限不是一味砍,而是按角色分层:dba\_readonly、dba\_admin、app\_writer,每层之间用视图或代理做隔离。










