生产环境mysql严禁业务或开发人员用root账号直连数据库,必须删除root@'%'账户、限制root仅限localhost访问、按最小权限原则为业务创建专用账号并禁用高危权限,定期巡检权限配置以防漂移。

生产环境 MySQL 绝对不能让业务应用或开发人员直接用 root 账号连接数据库——这不是“建议”,而是安全底线。
root@'%' 远程登录等于在防火墙上开个洞,还把钥匙焊死在洞口
只要存在 root@'%' 这条记录(运行 SELECT User, Host FROM mysql.user WHERE User = 'root'; 就能确认),攻击者就无需破解密码,只需连上 3306 端口,再配合暴力猜解或中间人劫持,就能拿到最高权限。真实案例中,有团队因漏删该账号,被扫描器 2 分钟内拖走全部用户表。
-
root@'localhost' 和root@'127.0.0.1' 是两个不同账户,前者走 socket,后者走 TCP;只留前者不代表防住了-h 127.0.0.1的远程连接 - MySQL 8.0+ 权限缓存机制下,
UPDATE mysql.user SET host = 'localhost'不生效,必须用DROP USER 'root'@'%'; - 即使开了防火墙,也得同步改配置:
bind-address = 127.0.0.1+FLUSH PRIVILEGES;+ 云安全组封 3306 入向
GRANT ALL PRIVILEGES ON *.* 不是省事,是埋雷
给业务账号执行 GRANT ALL PRIVILEGES ON *.* TO 'appuser'@'10.20.30.%';,等于授权它删库、关服务、读取系统表、写入文件(如果开了 FILE 权限)。一旦应用被 SQL 注入或配置泄露,攻击者不用提权,直接执行 DROP DATABASE shop_db; 或 SELECT ... INTO OUTFILE '/var/www/shell.php';。
- 正确做法是按服务建专用账号,比如
shop_order_rw,只授SELECT, INSERT, UPDATE ON shop_db.orders - 禁止授予
GRANT OPTION、CREATE USER、PROCESS、SHUTDOWN等高危权限 - 新建库后,
root@'%' 并不会自动获得该库的SELECT权限——GUI 工具切换库时触发的隐式查询会直接报Access denied for user 'root'@'%' to database 'xxx'
权限没回收,比没设权限更危险
很多团队上线时建了临时调试账号,事后忘了删。这些账号往往绑着 '%' 主机名、弱密码、且拥有 ALL PRIVILEGES。巡检脚本里必须固化这三行:
SELECT User, Host FROM mysql.user WHERE User IN ('root', 'mysql.sys', 'debian-sys-maint') AND Host = '%';
SELECT user, host FROM mysql.user WHERE account_locked = 'Y';
SHOW GRANTS FOR 'appuser'@'10.20.30.%';
第一行返回非空即高危;第二行查是否有人手动锁了账号却没通知;第三行看实际授予的权限是否超出当前业务需求——尤其是有没有意外继承 PROXY 或 CREATE USER 权限。
真正难的不是“怎么加权限”,而是“怎么确保每次删库、换人、下线服务时,权限也同步清理”。权限漂移比初始配置错误更隐蔽,也更常被忽略。











