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,每层之间用视图或代理做隔离。
