mysql 8.0+ 中仅查 mysql.user 表的 super_priv 字段会漏检大量真实拥有 super 权限的用户,必须结合 mysql.role_edges 和角色继承链三步闭环验证,并通过实操(如 kill query)确认权限生效。

Super_priv 字段查出来的是“显式授予”的账号,但 MySQL 8.0+ 中大量真实拥有 SUPER 权限的用户根本不会出现在这个结果里——只查 mysql.user 表一定会漏人。
直接查 mysql.user 表只能覆盖 MySQL 5.7 及更早版本
执行 SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y'; 是最快速的一线筛查动作,但它在 MySQL 8.0+ 已失效:
-
Super_priv大小写敏感:必须是Super_priv,写成super_priv或SUPER_PRIV会返回空或报错 - 刚执行过
GRANT SUPER ON *.* TO 'u'@'h'但没运行FLUSH PRIVILEGES,表中仍为'N',而权限已实际生效 -
mysql.session、mysql.infoschema这类系统账户也显示'Y',但它们不能登录,不算可被滥用的账号 - 该查询完全忽略角色继承路径,而 8.0+ 中绝大多数
SUPER权限都来自角色
MySQL 8.0+ 必须补查 mysql.role_edges 和角色权限链
角色本身不存 SUPER 权限,但可通过角色继承获得。验证需三步闭环:
- 先查绑定关系:
SELECT FROM_USER, FROM_HOST, TO_ROLE FROM mysql.role_edges; - 对每个
TO_ROLE执行:SHOW GRANTS FOR 'role_name'@'%';(注意:角色名必须带主机名,否则报错) - 若输出含
GRANT SUPER ON *.* TO,再反查谁绑定了该角色:SELECT User, Host FROM mysql.user u JOIN mysql.role_edges r ON u.User = r.FROM_USER AND u.Host = r.FROM_HOST WHERE r.TO_ROLE = 'xxx'; - 关键前提:用户必须已执行过
SET ROLE 'xxx';,否则即使查到角色链,当前会话也无SUPER
SHOW GRANTS 永远不显示 SUPER,别靠它判断
SHOW GRANTS FOR 'u'@'h' 输出里永远不会出现 SUPER 关键字,这是 MySQL 内部设计限制,不是你操作有误:
- 它只展示显式执行过的
GRANT语句,不解析角色继承、不读取mysql.user字段快照 -
GRANT ALL PRIVILEGES ON *.* TO不等于有SUPER(ALL不包含SUPER) - 真正验证方式只有登录后实操:
KILL QUERY 1;或SET GLOBAL max_connections = 1000;—— 成功即生效 - 批量检查时无法依赖
SHOW GRANTS,它每次只能查一个用户,且不支持跨角色链自动展开
删掉带 SUPER 的角色不会自动清理已授权用户
这是最容易被忽略的运维盲点:执行 DROP ROLE 'xxx'; 后,所有曾被授予该角色的用户,只要没显式 REVOKE,其 SUPER 权限依然存在(直到下次重启或手动刷新权限)。
角色权限不写入 mysql.user 表,也不触发自动清理;必须人工确认并执行 REVOKE 'xxx' FROM 'u'@'h'; 才能真正回收。











