应重点检查mysql.user表中super_priv和grant_priv是否被滥用,因其赋予用户绕过限制和授予权限的能力;需筛查高危账号、验证Host匹配、确认权限层级生效顺序及版本差异影响。
查 mysql.user 表里 super_priv 和 grant_priv 是否被滥用
这两个权限是 mysql 权限体系里的“核按钮”:开启 super_priv 的用户能绕过大多数限制(如修改只读模式、杀连接、写日志),而 grant_priv 允许用户再把权限授给其他人——一旦失控,整个权限链就不可控。
常见错误现象是批量建账号脚本里无差别赋予 ALL PRIVILEGES,结果让普通运维账号也带上了 Grant_priv='Y'。这类账号哪怕只配了 SELECT,也能把自己升级成 DBA。
- 执行
SELECT User, Host, Super_priv, Grant_priv FROM mysql.user WHERE Super_priv='Y' OR Grant_priv='Y';快速筛出高危账号 - 重点比对同名用户在不同
Host上是否重复开启(比如'admin'@'localhost'和'admin'@'%'都开了Super_priv) - phpMyAdmin 的“用户账户”页只显示当前登录用户可见的权限,要查全量必须用 root 或具备
SELECT权限的账号访问mysql库
确认数据库级权限是否覆盖了表级权限
MySQL 权限按层级生效:全局 → 数据库 → 表 → 列。如果用户已对 myapp.* 有 ALL,再单独给 myapp.users 表赋 SELECT 就纯属冗余——不仅没用,还会在后续删库级权限时留下残留表权限,造成误判。
迁移旧系统或执行历史脚本时最常踩这个坑:一堆零散 GRANT SELECT ON mydb.table1 TO 'u'@'h'; 被反复执行,却没人检查上层是否已有更高权限。
- 查库级权限:
SELECT User, Host, Db, Select_priv, Insert_priv FROM mysql.db WHERE Db='myapp'; - 查表级权限:
SELECT User, Host, Db, Table_name, Table_priv FROM mysql.tables_priv WHERE Db='myapp'; - 判断逻辑很简单:若某用户在
mysql.db中对某库的Select_priv='Y',则mysql.tables_priv中同库同用户的任何Table_priv都可视为冗余(MySQL 不支持 DENY,所以不存在“覆盖抵消”)
验证 Host 匹配是否导致权限失效
MySQL 用户是 'user'@'host' 二元组,'u'@'localhost' 和 'u'@'127.0.0.1' 是两个完全独立的账号,权限不共享。很多“权限明明给了却连不上”的问题,根源都在这里。
立即学习“PHP免费学习笔记(深入)”;
典型场景:phpMyAdmin 创建用户时默认填 localhost,但命令行用 mysql -u u -p 在 Windows 下实际走的是 TCP 连接(等价于 127.0.0.1),结果找不到匹配的权限记录。
- 先用
SELECT User, Host FROM mysql.user;确认目标用户是否存在、Host值是否和你连接方式一致 - Linux/macOS 下 socket 连接匹配
localhost,TCP 连接匹配127.0.0.1;Windows 默认走 TCP,除非显式加--protocol=socket - 生产环境慎用
'%',它不匹配localhost(MySQL 内部规则),反而可能漏掉本地管理需求
检查权限是否真的已生效(别信 phpMyAdmin 的“刷新”)
phpMyAdmin 提交权限后不会自动执行 FLUSH PRIVILEGES,新版 MySQL(8.0+)已改用动态权限表,改完即生效;但 5.7 及更早版本仍依赖手动刷新,否则新权限不加载。
更隐蔽的问题是权限继承:删了 mysql.db 里的某条记录,不代表用户失权——他可能还从 mysql.user 继承了 Super_priv='Y',照样能操作所有库。
- 清理前务必按顺序检查:
mysql.user→mysql.db→mysql.tables_priv→mysql.columns_priv - 清理后不要只点 phpMyAdmin 的“刷新”按钮,要用新连接实测:
mysql -u testuser -p -h 127.0.0.1(强制 TCP)或mysql -u testuser -p -S /var/run/mysqld/mysqld.sock(强制 socket) - 用
SHOW GRANTS FOR 'testuser'@'127.0.0.1';查看最终生效的权限语句,这是唯一可信来源



















