不能直接从information_schema查到所有用户的完整权限分布,因其不存储权限数据;MySQL权限仅存于mysql系统库的user、db、tables_priv等表中,需联合查询或用SHOW GRANTS展开角色继承关系。

不能直接从 information_schema 查到所有用户的完整权限分布——它压根不存权限数据。MySQL 的权限信息只在 mysql 系统库的几张表里,information_schema 里没有任何一张表包含用户权限字段。
为什么查 information_schema 会一无所获
很多人误以为 information_schema 是“数据库的元数据中心”,理应包含权限视图。但实际它只暴露结构信息(如表名、列名、索引),**不暴露访问控制规则**。你执行 SELECT * FROM information_schema.SCHEMATA 或 TABLES,连 GRANTEE 字段都找不到。
-
information_schema.ROLE_TABLE_GRANTS和ROLE_COLUMN_GRANTS在 MySQL 8.0+ 确实存在,但它们只记录「角色对对象的授权」,不记录「用户直授权限」或「用户继承的角色」 -
information_schema.APPLICABLE_ROLES只显示当前会话已激活的角色,不是全量用户角色映射 - 想靠
information_schema拼出“谁对哪个库/表有 SELECT 权”,注定失败
真正该查的三张核心表及其陷阱
权限按层级分散存储,漏掉任意一张,就等于漏掉一部分真实权限:
-
mysql.user:只含全局权限(如Super_priv、Shutdown_priv),但Select_priv这类字段是 Y/N 值,不是可读字符串 -
mysql.db:库级权限,注意Db字段区分大小写,且User和Host必须与mysql.user完全匹配才能生效(比如'user'@'192.168.%'和'user'@'%'是两个不同条目) -
mysql.tables_priv:表级权限,Table_priv是逗号分隔字符串(如'Select,Insert'),不能用= 'Select'直接匹配,得用FIND_IN_SET('Select', Table_priv)
别忘了还有 mysql.columns_priv(列级)和 mysql.role_edges(角色继承关系),批量审计时必须 LEFT JOIN 进来,否则“某用户能查 user 表但不能查 phone 列”这种细粒度限制就看不到了。
一条能跑通的聚合查询(带防截断)
下面这条 SQL 能把用户、库、表三级权限合并到一行,适合导出 CSV 后人工筛查:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
SET SESSION group_concat_max_len = 1000000; SELECT u.User, u.Host, u.authentication_string AS auth, CONCAT(u.Select_priv, u.Insert_priv, u.Update_priv, u.Delete_priv) AS global_dml, GROUP_CONCAT(DISTINCT CONCAT(d.Db, ':', d.Select_priv, d.Insert_priv) SEPARATOR ';') AS db_privs, GROUP_CONCAT(DISTINCT CONCAT(t.Db, '.', t.Table_name, ':', t.Table_priv) SEPARATOR ';') AS table_privs 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 GROUP BY u.User, u.Host, u.authentication_string;
关键点:
- 必须先执行
SET SESSION group_concat_max_len = 1000000,否则默认 1024 字符会 silently 截断长权限列表 - 用
CONCAT(d.Db, ':', ...)而不是裸字段,是为了避免空值干扰分组 - 结果里
global_dml是 Y/N 拼接,需人工对照(Y=有权限,N=无),不能直接当布尔值用
更稳妥的替代方案:用 SHOW GRANTS 批量生成
如果目标是生成可审计、可比对的权限语句(而非聚合视图),别硬拼 SQL,改用脚本驱动 SHOW GRANTS:
- 先查出所有用户:
SELECT User, Host FROM mysql.user - 对每行执行:
SHOW GRANTS FOR 'User'@'Host' - 用 shell 或 Python 把结果逐条保存,避免 JOIN 逻辑错漏
- 注意:MySQL 8.0 默认禁用
SELECT对mysql库的访问,执行前确认当前账号有SELECT权限在mysql.*上
最易被忽略的是角色权限的穿透性——SHOW GRANTS 会自动展开用户拥有的角色及其权限,而手工 JOIN mysql.role_edges 很容易漏掉多层继承(比如 A→B→C),这点在生产环境权限复核时极关键。










