查 mysql.user 表的 super_priv 字段是最快方式,但 mysql 8.0+ 必须联查 mysql.role_edges 补全角色继承链,否则漏人;show grants 永不显示 super,验证需实际执行 kill query 等操作。

查 mysql.user 表的 Super_priv 字段是最快、最直接的方式,但 MySQL 8.0+ 必须额外检查角色继承链,否则一定漏人。
直接查 mysql.user 表的 Super_priv 字段(MySQL 5.7 及之前)
这个字段在旧版本中就是最终生效状态的快照,不依赖角色、不走视图、不缓存中间态。执行:
SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y';
注意以下几点:
-
Super_priv大小写敏感:必须大写 S 和 P,写成super_priv或SUPER_PRIV会报错或查不到 - 执行者需有
SELECT ON mysql.*权限,普通用户默认没有,得用root或带SYSTEM_USER角色的账号 - 刚执行过
GRANT SUPER ON *.* TO 'u'@'h'但没运行FLUSH PRIVILEGES,表里可能还是'N',而权限实际已生效——此时SHOW GRANTS才是真实依据 -
mysql.session、mysql.infoschema这类系统账户也显示Super_priv = 'Y',但它们不能登录,不算 DBA 可用的“真实”超级账号
MySQL 8.0+ 必须联查 mysql.role_edges 补角色继承路径
8.0 引入角色后,Super_priv = 'Y' 不再覆盖全部情况:用户可以没直连 'Y',却通过角色间接获得 SUPER。角色本身不能被显式授予 SUPER(GRANT SUPER ON *.* TO 'role'@'%' 会报错),但角色可被赋予含 SUPER 的权限组合(例如升级残留或手动改表),且用户激活后即生效。
实操分两步:
- 先查谁绑定了角色:
SELECT TO_USER, TO_HOST, FROM_USER, FROM_HOST FROM mysql.role_edges;
- 对每个查到的
FROM_USER(即角色名),再查它自己是否被设为Super_priv = 'Y':SELECT User, Host FROM mysql.user WHERE User = 'role_name' AND Host = '%' AND Super_priv = 'Y';
注意:角色名也需带主机名(如'myadmin'@'%'),否则后续SHOW GRANTS FOR会失败
关键提醒:用户必须已执行 SET ROLE 'xxx'; 才能激活角色权限;否则即使查到角色链,实际也无 SUPER。
SHOW GRANTS 永远不显示 SUPER,别信它
SHOW GRANTS FOR 'u'@'h' 输出里永远不出现 SUPER 字样,哪怕用户真有该权限。这是 MySQL 内部设计限制,不是你查错了。
它只展示显式 GRANT 语句,不解析角色继承、不读取 mysql.user 字段快照。所以:
- 没看到
GRANT SUPER ON *.* TO,不代表没权限——可能是角色继承,也可能是早期用INSERT INTO mysql.user直接改过字段 - 验证是否真能用:登录该账号后执行
KILL QUERY或SET GLOBAL max_connections = 1000,比看语句更直接
权限回收时 DROP ROLE 不等于清除 SUPER
删掉一个带 SUPER 的角色,并不会自动清理已通过该角色获得权限的用户字段——因为权限在用户行里是静态快照,不是实时计算的。
删角色后,原用户仍可能保留,除非你显式执行:
REVOKE SUPER ON *.* FROM 'u'@'h';
REVOKE 对角色无效:REVOKE SUPER ON *.* FROM 'myrole'; 会报错,因为角色不能持有 SUPER。
真正要做的,不是找“谁有 SUPER”,而是确认它从哪来、能不能被回收、会不会因角色变更而意外残留。











