查 mysql.user 表 Super_priv='Y' 是基础但不足,MySQL 8.0+ 需联查 role_edges 补角色链,SHOW GRANTS 不显示 SUPER,实际权限须结合快照、角色激活状态与操作验证三者比对。

查 mysql.user 表里的 Super_priv 字段是最快、最基础的动作,但仅靠它在 MySQL 8.0+ 中一定会漏人——因为角色继承的 SUPER 权限不写入该字段,且 SHOW GRANTS 永远不会显示它。
直接查 mysql.user 表的 Super_priv = 'Y'
这是所有版本都必须跑的第一步,反映的是用户行级权限快照(非实时,但可查):
-
Super_priv必须严格大写 S 和 P;写成super_priv或SUPER_PRIV会报错或返回空 - 必须用有
SELECT ON mysql.*权限的账号执行,比如root或带SYSTEM_USER角色的用户 - 结果中
Host值必须和实际连接完全一致:'localhost'≠'127.0.0.1'≠'%' -
mysql.session、mysql.infoschema这类系统账户也显示'Y',但它们不能登录,不算真实可滥用账号 - 刚执行过
GRANT SUPER ON *.* TO 'u'@'h'但没运行FLUSH PRIVILEGES,表里可能仍是'N',而权限已生效——此时SHOW GRANTS才是真实依据
MySQL 8.0+ 必须联查 mysql.role_edges 补角色链
只查 mysql.user 会漏掉通过角色间接获得 SUPER 的活跃连接,因为角色权限不写入用户行,且需显式激活:
- 先查谁绑了角色:
SELECT FROM_USER, FROM_HOST, TO_ROLE FROM mysql.role_edges; - 对每个
TO_ROLE,执行SHOW GRANTS FOR 'role_name'@'%';—— 注意角色名必须带主机名,否则失败 - 若输出含
GRANT SUPER ON *.* TO,说明该角色链能提供 SUPER - 再反查哪些用户被授了这个角色:
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 对 SUPER 是个“盲区”,不是你操作错了,而是 MySQL 内部设计如此:
-
SHOW GRANTS FOR 'u'@'h'输出里永远不出现SUPER关键字,哪怕用户真有 - 它只展示显式
GRANT语句,不解析角色继承,也不读取mysql.user字段快照 - 没看到
GRANT SUPER ON *.* TO,不代表没权限——可能是角色继承,也可能是早期用INSERT INTO mysql.user直接改过字段 - 验证是否真能用:登录该账号后执行
KILL QUERY 1;或SET GLOBAL max_connections = 1000;,比看语句更直接
权限回收后 Super_priv 字段不会自动清零
删角色、撤授权都不等于清除字段值,因为 mysql.user 里的权限是静态快照,不是实时计算的:
-
DROP ROLE 'myadmin';不会自动把关联用户的Super_priv改回'N' -
REVOKE SUPER ON *.* FROM 'u'@'h';才会更新字段,但也需配合FLUSH PRIVILEGES才能确保后续查询一致 - 旧版本升级残留、手动改表、未刷新的权限缓存,都会导致字段值与实际行为不一致
真正要确认“当前连接是否有 SUPER”,不能只靠查表或看语句,得结合 mysql.user 快照 + 角色激活状态 + 实际操作验证三者交叉比对。最容易被忽略的是:权限检查发生在每次执行高危操作(如 KILL、SET GLOBAL)时,而不是连接建立那一刻。


















