查mysql所有用户权限需综合mysql.user、mysql.db、mysql.tables_priv、mysql.columns_priv及mysql.role_edges等表,因权限按全局、库级、表级、列级和角色分层存储,单查任一表均不完整。

查 MySQL 所有用户权限用哪几张系统表
MySQL 的权限信息分散在 mysql.user、mysql.db、mysql.tables_priv、mysql.columns_priv 等多张系统表里,直接查 mysql.user 只能看到全局权限(比如 SELECT_priv、Super_priv),但看不到库级、表级甚至列级的细粒度授权——那些都在别的表里。
真正想“审计所有权限”,不能只看一张表。常见错误是只跑 SELECT * FROM mysql.user,结果漏掉 80% 的实际权限配置。
-
mysql.user:记录用户连接信息 + 全局权限(Grant_priv、Shutdown_priv等) -
mysql.db:按数据库维度控制权限(Select_priv、Insert_priv等),字段含Db和User -
mysql.tables_priv:表级权限,注意Table_name是明文存储,Table_priv是逗号分隔字符串(如'Select,Insert') -
mysql.columns_priv:列级权限,更少见但存在,Column_priv同样是逗号分隔
一条 SQL 拼出用户+库+表三级权限视图
手动 JOIN 多张表容易漏条件或重复,最实用的是用 SHOW GRANTS FOR 'user'@'host',但它只能查单个用户。批量审计时,得自己拼一个“近似完整”的权限快照。
下面这条 SQL 能把大部分权限聚合到一行,适合导出后人工筛查:
SELECT u.User, u.Host, u.authentication_string AS auth, CONCAT(u.Select_priv, u.Insert_priv, u.Update_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;
注意:GROUP_CONCAT 默认长度限制是 1024 字符,如果某用户权限特别多,会截断——执行前先设 SET SESSION group_concat_max_len = 1000000;。
为什么不能直接 SELECT * FROM mysql.*_priv 表
这些权限表不是为直接查询设计的,字段值大多是 Y/N 或逗号分隔字符串,没做标准化解析。比如 mysql.tables_priv.Table_priv 存的是 'Select,Insert,Update',不是布尔字段,也不能直接 WHERE Table_priv = 'Select' ——得用 FIND_IN_SET('Select', Table_priv) 或正则匹配,性能差且易出错。
- 权限字段大小写敏感(
'select'≠'Select') -
mysql.db中Db字段支持通配符(如'test%'),直接等值匹配会漏授权 - 部分权限依赖生效顺序:比如
mysql.user拒绝了SELECT,但mysql.db又允许了同库的SELECT,最终以“最具体匹配”为准,SQL 无法自动模拟这个逻辑
audit 用户权限必须搭配 FLUSH PRIVILEGES 吗
不需要。所有权限表(mysql.*)是内存+磁盘双份,SELECT 查的是当前内存中加载的权限快照,和磁盘数据一致——除非你刚改过表但没 FLUSH PRIVILEGES,那查到的就是旧状态。
也就是说:如果你只是读权限,不修改,就不用管 FLUSH;但如果你 audit 发现异常、准备修复(比如 UPDATE mysql.user SET Select_priv='N'),改完必须立刻 FLUSH PRIVILEGES,否则新权限不生效。
容易被忽略的一点:MySQL 8.0+ 引入了角色(roles),权限可能通过 mysql.role_edges 间接授予,上面所有查询都看不到这部分——要加 mysql.role_edges 和 mysql.role_routines_priv 等关联表才能覆盖完整。











