SHOW GRANTS FOR 'user'@'host' 是最可靠的一键审计方式,它动态合并全局、库、表、列等所有显式权限为可执行GRANT语句,避免手动JOIN系统表的兼容性与逻辑问题。
直接查 mysql.user 表只能看到全局权限,不完整
很多人在 phpmyadmin 的 sql 标签页里执行 select * from mysql.user,以为这就看清了所有权限——其实只拿到了冰山一角。mysql 的权限是分层存储的:mysql.user 只存全局权限(如 select_priv、super_priv),而数据库级权限在 mysql.db,表级在 mysql.tables_priv,列级在 mysql.columns_priv。phpmyadmin 界面默认不自动 join 这些表,所以单看 mysql.user 会漏掉大量实际生效的权限。
常见错误现象:某用户明明没勾选数据库权限,却能操作某个库——大概率是因为 mysql.db 里有残留记录,或该用户在 mysql.user 里开了 Super_priv = 'Y',直接绕过所有层级检查。
- MySQL 8.0+ 中
mysql.tables_priv.Table_priv存的是逗号分隔字符串(如'Select,Insert'),不是布尔值,不能用= 'Y'判断 -
mysql.user的字段名大小写敏感,且不同版本差异大(5.7 有Grant_priv,8.0 新增Account_locked) - 查
mysql.db时必须同时匹配User和Host,否则可能查到其他同名用户的权限
SHOW GRANTS FOR 'user'@'host' 是最可靠的一键审计方式
比起手动 JOIN 多张系统表,SHOW GRANTS 是 MySQL 服务端动态合成的结果,它把全局、库、表、列、过程等所有显式授予的权限合并成可执行的 GRANT 语句,天然规避了字段兼容性和逻辑拼接问题。这是 phpMyAdmin 内部“编辑权限”页面背后真正依赖的机制。
实操建议:
- 在 phpMyAdmin 的 SQL 标签页中直接运行:
SHOW GRANTS FOR 'app_user'@'localhost'; - 如果报错
Access denied,说明当前登录账号没有SELECT权限在mysql库,或缺少SYSTEM_USER特权(MySQL 8.0.17+) - 输出中带
WITH GRANT OPTION的行,表示该用户能转授对应权限;但不会显示已转授给谁——这部分信息不落盘,只存在于运行时授权链中 - 对多个用户批量检查,需逐条执行
SHOW GRANTS,无法一次查全部(MySQL 不支持SHOW GRANTS FOR USER IN ('u1','u2'))
用导出 SQL 实现「伪批量」权限快照比对
phpMyAdmin 的「用户账户」页支持勾选多个用户后点击「导出所选用户」,生成包含 CREATE USER、GRANT、SET PASSWORD 的完整 SQL 文件。这不是实时权限快照,而是当前显式授予状态的静态快照,但它能帮你快速发现异常模式——比如多个开发账号都意外拥有 SUPER 权限,或测试账号被误授了 DROP。
立即学习“PHP免费学习笔记(深入)”;
关键操作点:
- 导出前务必勾选「添加 CREATE USER 语句」和「添加 SET PASSWORD 语句」,否则导入时会因用户不存在失败
- 打开导出的 SQL 文件,搜索
GRANT ALL PRIVILEGES或SUPER,定位高危配置 - 对比不同用户的
GRANT行,看是否存在冗余覆盖(例如某用户已有GRANT ALL ON mydb.*,又单独给了GRANT SELECT ON mydb.users) - 不要依赖导出文件里的密码哈希值做安全审计——它只是当前存储值,不代表是否被轮换或泄露
权限冲突时,FLUSH PRIVILEGES 不是万能解药
很多用户发现改完权限后新连接仍无效果,第一反应是点 phpMyAdmin 右上角的「刷新权限表」按钮(本质是执行 FLUSH PRIVILEGES)。但这一步只解决「权限表已更新但内存缓存未重载」的问题,无法掩盖更深层的冲突根源。
真正容易被忽略的是 host 匹配和权限继承链:
-
'user'@'localhost'和'user'@'%'是两个完全独立的用户,改其中一个不影响另一个 - 若用户在
mysql.user有Super_priv = 'Y',删掉mysql.db里的所有记录也无效——超级权限直接跳过所有下层检查 - MariaDB 10.4+ 若启用
skip-grant-tables,FLUSH PRIVILEGES完全无效,必须关闭该配置并重启mysqld - phpMyAdmin 界面修改权限后,即使点了「执行」,也不代表语句已提交成功——要检查返回的 SQL 执行结果,确认没有
ERROR 1045或ERROR 1142



















