无法用单条命令查出所有用户完整权限列表,因mysql 8.0+权限分层分散,show grants仅支持单用户且不支持变量批量执行,系统表需手动联查,角色权限还需额外处理并验证刷新与启用状态。

不能直接用一条命令查出所有用户的完整权限列表。MySQL 8.0+ 的权限模型是分层、分散且动态的,SHOW GRANTS 只对单个用户有效,而系统表(如 mysql.user)只存全局权限,漏掉库级、表级、角色继承等关键部分。
为什么 SHOW GRANTS FOR 不能批量执行
MySQL 不支持 SHOW GRANTS FOR * 或类似语法。每个 SHOW GRANTS FOR 'u'@'h' 都需显式指定用户名和 host,且执行者必须有 SELECT 权限访问 mysql.user 表——普通用户默认无权查他人权限,会报 ERROR 1045 (28000)。
- 即使你是 root,也不能用存储过程或循环自动遍历所有用户并执行
SHOW GRANTS,因为该语句不支持变量绑定(PREPARE+EXECUTE对SHOW类语句无效) -
SHOW GRANTS输出是文本格式,不是结果集,无法用JOIN或UNION合并 - 若用户绑定了角色但未启用(
SET ROLE),SHOW GRANTS FOR也不会展开角色内权限,只显示ROLE = 'xxx'
真正能拼出“所有用户权限”的组合查询
必须手动联查多个系统表,并理解每张表的权限粒度:
-
mysql.user:仅全局权限(如Select_priv),MySQL 8.0+ 中多数字段已弃用,仅作兼容参考 -
mysql.db:库级权限(Db,Select_priv等),注意User和Host必须完全匹配 -
mysql.tables_priv:表级权限,Table_name是 base64 编码值,需用FROM_BASE64(Table_name)解码才可读 -
mysql.role_edges:记录谁被授了哪个角色(To_user,To_host,From_role) -
INFORMATION_SCHEMA.ROLE_TABLE_GRANTS:角色实际拥有的库/表权限(MySQL 8.0.17+)
一个最小可用的跨层级汇总示例(需 root 权限):
SELECT u.User, u.Host, u.Select_priv AS global_select, d.Db, d.Select_priv AS db_select, t.Table_schema, t.Table_name, t.Table_priv, r.From_role FROM mysql.user u LEFT JOIN mysql.db d ON u.User = d.User AND u.Host = d.Host LEFT JOIN mysql.tables_priv t ON u.User = t.User AND u.Host = t.Host LEFT JOIN mysql.role_edges r ON u.User = r.To_user AND u.Host = r.To_host WHERE u.User != '';
更实用的替代方案:逐个导出 + 脚本化
与其硬拼大而全的 SQL,不如用 shell 脚本驱动 MySQL 客户端批量生成权限快照:
- 先用
SELECT User, Host FROM mysql.user;拿到全部账号列表 - 对每一行构造
SHOW GRANTS FOR 'user'@'host';,重定向到文件 - 注意处理特殊字符:host 含
%或下划线时,mysql命令行需加引号,否则 shell 会误展开 - 角色权限要额外补查:
SHOW GRANTS FOR ROLE 'rolename';,再人工合并 - 别忘了验证
CURRENT_USER()和USER()差异——同一个用户名从不同 host 登录,可能匹配到完全不同权限的记录
最易被忽略的一点:你看到的“权限列表”,永远只是静态配置快照;真实生效权限还取决于是否执行过 FLUSH PRIVILEGES(MySQL 8.0+ 大多自动刷新,但某些插件或自定义部署仍依赖手动触发),以及当前会话是否启用了对应角色(SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;)。不确认这两点,任何权限查询结果都可能滞后于实际行为。











