查mysql.user表不可信,MySQL 8.0+中Super_priv等字段不反映实时权限,需结合mysql.global_grants、SHOW GRANTS、mysql.role_edges及mysql.db通配符行交叉验证。

查mysql.user表只能筛出部分高危账号,但结果不可信
MySQL 8.0+ 中 mysql.user 表里的 Super_priv、Grant_priv 等字段已不反映实时权限状态,它们只在初始化或执行 FLUSH PRIVILEGES 后同步一次,且不包含角色继承、动态权限等真实生效项。直接跑 SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y' 可能漏掉大量真正拥有 SUPER 的用户。
实操建议:
- 先确认版本:
SELECT VERSION();,若 ≥ 8.0.16,优先查mysql.global_grants - 对每个非系统用户(排除
'mysql.infoschema'、'mysql.session'等)执行SHOW GRANTS FOR 'u'@'h',这是唯一权威方式 - 注意
SHOW GRANTS输出中是否含ON *.*和WITH GRANT OPTION,两者同时出现即为高危组合
用mysql.global_grants快速定位显式授予的全局权限
mysql.global_grants 是 MySQL 8.0.16+ 引入的权威表,专用于记录 GLOBAL 级别显式授权,字段 privilege 值为 'ALL PRIVILEGES'(注意带空格和复数),不是 'ALL';with_grant_option 为 'Y' 表示可转授。
实操建议:
- 运行:
SELECT user, host, privilege, with_grant_option FROM mysql.global_grants WHERE privilege IN ('ALL PRIVILEGES', 'SUPER', 'REPLICATION CLIENT'); - 该表不包含角色继承权限——若用户通过角色获得
ALL PRIVILEGES ON *.*,此查询不会返回,必须额外查mysql.role_edges - 搭配
mysql.default_roles查用户启用的角色:SELECT * FROM mysql.default_roles WHERE USER = 'u' AND HOST = 'h';
别忽略mysql.db里的“伪全局权限”
有些账号没被授 ON *.*,却对所有数据库有操作权:当 mysql.db 表中某行的 Host 为 '%' 且 Db 为 '*'(通配符,非字面星号),就等效于全局权限。phpMyAdmin 和多数界面工具完全不显示这类配置。
实操建议:
- 查伪全局:
SELECT User, Host, Db FROM mysql.db WHERE Host = '%' AND Db = '*'; - 这类账号常被误认为“仅库级”,实际权限范围与
Super_priv='Y'用户接近,尤其当Select_priv='Y'、Insert_priv='Y'等同时为'Y'时 - 检查时需连带看
mysql.tables_priv是否存在同用户同主机的更细粒度覆盖,避免误判
audit日志里为什么找不到SUPER操作?三个必检点
即使开了 server_audit 插件,日志也可能为空——问题常卡在底层依赖未就绪。最易漏的是:
-
performance_schema必须开启:SHOW VARIABLES LIKE 'performance_schema';返回ON,否则事件上下文采集失败 -
server_audit_events必须含'CONNECT,QUERY_DDL':SET GLOBAL server_audit_events = 'CONNECT,QUERY_DDL,QUERY_DML';,漏掉QUERY_DDL就记录不了SET GLOBAL、INSTALL PLUGIN -
server_audit_excl_users别误加 DBA 账号:root或运维账号若被排除,关键操作将彻底消失在日志里
真正要盯住的不是日志有没有,而是 performance_schema 是否启用、QUERY_DDL 是否在事件列表里、以及被审计账号是否真的没被排除——这三点错一个,审计就形同虚设。


















