information_schema.user_privileges不可信,因其仅映射显式grant的全局权限,不读取mysql.user表字段,且忽略直接修改、角色继承、代理用户等权限来源。

直接查 information_schema.USER_PRIVILEGES 看不到真实全局权限,它只返回 USAGE,不能用于审计或排障。
为什么 USER_PRIVILEGES 表不可信
这个表是 MySQL 的非标准元数据视图,设计上只映射“显式 GRANT 出来的全局权限”,但实际权限存储在 mysql.user 表里。哪怕你用 UPDATE mysql.user SET super_priv = 'Y' 直接改了字段,USER_PRIVILEGES 也不会体现——它压根不读那个字段。更麻烦的是,它把所有没走 GRANT 流程的权限(比如直接写表、角色继承、代理用户)全过滤掉了。
常见错误现象:SELECT * FROM information_schema.USER_PRIVILEGES WHERE GRANTEE = "'appuser'@'localhost'" 返回空或只有 USAGE,但用户明明能执行 KILL 或 SHOW PROCESSLIST——说明权限来自 mysql.user 的 process_priv 或 super_priv 字段,而这个表根本不管这些。
查库级权限该盯哪张表:优先用 SCHEMA_PRIVILEGES
这是最接近“谁对哪个库有啥权限”的直观看法,尤其适合快速定位谁有 UPDATE 或 DROP 权限:
SELECT GRANTEE, TABLE_SCHEMA, PRIVILEGE_TYPE, IS_GRANTABLE FROM INFORMATION_SCHEMA.SCHEMA_PRIVILEGES WHERE PRIVILEGE_TYPE IN ('SELECT', 'UPDATE', 'DELETE')-
GRANTEE是'user'@'host'格式,注意单引号要保留;匹配时可用TRIM(BOTH "'" FROM GRANTEE)清理引号再做字符串比对 - 它只反映
GRANT ... ON db_name.*这类库级授权,不包含GRANT ... ON db_name.tbl_name(表级)或GRANT ... (col) ON ...(列级) - MySQL 8.0+ 启用角色后,如果权限来自角色,
GRANTEE可能是角色名(如'dev_role'@'%'),需额外查APPLICABLE_ROLES关联实际用户
查表级和列级权限必须分两步:TABLE_PRIVILEGES + COLUMN_PRIVILEGES
很多“权限报错”其实卡在这两层。比如 UPDATE t1 SET x=1 报 ERROR 1142,但 SCHEMA_PRIVILEGES 显示有 UPDATE——大概率是权限只给了某几列,或只给了某张表,没给整个库。
- 查表级:
SELECT GRANTEE, TABLE_NAME, PRIVILEGE_TYPE FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE TABLE_SCHEMA = 'mydb' AND PRIVILEGE_TYPE = 'UPDATE' - 查列级:
SELECT GRANTEE, COLUMN_NAME, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 't1' AND PRIVILEGE_TYPE = 'UPDATE' -
TABLE_PRIVILEGES.GRANTEE可能是角色,不是用户;COLUMN_PRIVILEGES里甚至可能出现IS_GRANTABLE = 'NO',表示该列权限不可再转授 - 这两张表不包含全局权限(如
PROCESS)、动态权限(如BACKUP_ADMIN),也不反映DEFINER或PROXY用户行为
真正想看“当前连接实际能干啥”,别硬查表,用 SHOW GRANTS
SHOW GRANTS FOR 'u'@'h' 是唯一自动合并所有权限路径的结果:直接授予、角色继承、代理权限、DEFINER 上下文。它不保证底层字段值一致,但代表 MySQL 实际检查时的行为。
- 输出是逻辑语句(如
GRANT SELECT, INSERT ON *.* TO 'u'@'h'),不是原始存储值;所以它可能把多个来源的SELECT权限合并成一条 - 但它不会告诉你权限是否已修改但未
FLUSH PRIVILEGES——此时内存权限状态和磁盘不一致,SHOW GRANTS返回的是内存里的结果 - 如果用户属于多个角色,且部分角色被
SET ROLE激活,SHOW GRANTS只显示当前激活的角色权限,不是全部
复杂点在于:权限生效依赖内存加载,改完 mysql.user 必须 FLUSH PRIVILEGES,否则 SHOW GRANTS 和实际行为都会滞后;而 information_schema 里的各张表,只是对磁盘数据的快照,跟运行时权限不是一回事。











