phpMyAdmin“编辑权限”页面仅显示显式写入的权限记录,而MySQL实际生效权限是全局→数据库→表→列层级叠加的结果,故界面状态≠真实权限;应以SHOW GRANTS动态查询为准。
为什么直接看“编辑权限”页面不等于看到真实权限
phpmyadmin 的「编辑权限」页面只展示该用户在 mysql.user、mysql.db 等表中**显式写入的权限记录**,但 mysql 实际生效的权限是分层叠加的:全局 → 数据库 → 表 → 列。比如某用户在 mysql.user 里 select_priv = 'y',又在 mysql.db 里对 myapp 库开了 select_priv = 'n',最终他仍能查所有库(因为全局权限覆盖库级拒绝——mysql 不支持 deny)。所以界面勾选状态 ≠ 运行时能力。
用 SHOW GRANTS 查动态合成的真实权限
这才是最可靠的方式,MySQL 服务端会把所有层级权限合并成可执行的 GRANT 语句,绕过手动 JOIN 多张表的麻烦和字段兼容性问题。
- 在 phpMyAdmin 的 SQL 标签页执行:
SHOW GRANTS FOR 'app_user'@'localhost'; - 如果报错
ERROR 1142 (42000): SELECT command denied,说明当前登录账号没权限查其他用户——这不是 phpMyAdmin 限制,是 MySQL 权限体系本身要求,必须用 root 或有SELECT权限在mysql库的账号执行 - 输出里带
WITH GRANT OPTION的行表示该用户能转授对应权限;但不会显示已被他转授给谁——这部分信息不在任何系统表里持久化
查系统表时要注意字段差异和版本陷阱
直接读 mysql.user 只能看到全局权限,而 mysql.db、mysql.tables_priv 才存库/表级权限。但字段含义和格式随 MySQL 版本变化很大:
- MySQL 5.7 中
mysql.tables_priv.Table_priv是布尔值;8.0+ 改为逗号分隔字符串(如'Select,Insert'),得用FIND_IN_SET('Select', tp.Table_priv)判断 -
mysql.user在 8.0+ 新增了Account_locked、Password_reuse_history等字段,老版本没有,JOIN 时容易出错 - Host 匹配严格: 是两个完全独立的账号,权限不互通,也不能靠模糊匹配自动合并
phpMyAdmin 版本决定你能看到什么
新版和旧版的权限入口、默认展开项、甚至字段渲染逻辑都不同,不统一就容易误判:
- phpMyAdmin 4.0–4.2:没有顶部「Users」标签页,必须点右上角「Privileges」;「Global privileges」默认折叠在页面最底部,且必须手动选下拉框里的
All databases才能编辑 - phpMyAdmin 4.9+:默认隐藏「用户账户」选项卡,得先进入
mysql数据库 →user表 →Browse页才能看到列表 - MySQL 8.0+ 配合 caching_sha2_password 插件时,旧版 phpMyAdmin 会连
mysql.user表都查不出来(报错 #1142),不是权限问题,是驱动握手协议不兼容
SHOW GRANTS 输出为准,而不是界面勾选状态或某一张系统表的内容。尤其当涉及权限继承、多 Host 账号、或跨版本迁移时,漏掉任意一层都可能让判断失准。



















