在实际使用MySQL权限管理时,很多开发者会发现,虽然系统看似简单,但要准确找出“谁拥有最高权限”却容易踩坑。实际上,MySQL中并不存在一个名为“ALL PRIVILEGES”的独立字段。所谓的“全权限”状态,本质上是将mysql.user表中所有以_priv结尾的字段都设置为'Y',共计29个。一旦执行GRANT ALL PRIVILEGES,系统就会自动将这些开关全部开启。

查 mysql.user 表里哪些字段代表 ALL PRIVILEGES
因此,要判断某个用户是否拥有真正的“全权限”,就需要逐一检查这些权限字段。重点关注的是一串名字:Select_priv、Insert_priv、Update_priv、Delete_priv、Create_priv、Drop_priv、Reload_priv、Shutdown_priv、Process_priv、File_priv、Grant_priv、References_priv、Index_priv、Alter_priv、Show_db_priv、Super_priv、Create_tmp_table_priv、Lock_tables_priv、Execute_priv、Repl_sla ve_priv、Repl_client_priv、Create_view_priv、Show_view_priv、Create_routine_priv、Alter_routine_priv、Create_user_priv、Event_priv、Trigger_priv、Create_tablespace_priv —— 一共29个,这是MySQL 8.0+的完整清单。
但在实际应用中,真正构成“等效ALL”的核心权限,通常是前16到18个管理型与数据操作型字段。像Super_priv和Create_user_priv这样的高危特权是否需要包含,取决于你对“ALL”权限定义的严格程度。
用 SQL 精确匹配全部权限为 'Y' 的用户
直接查询mysql.user表,筛选出所有权限字段均为'Y'的行,听起来很简单,但有两个注意事项。第一,必须将所有目标字段用AND连接,缺一不可;第二,MySQL 8.0+默认使用caching_sha2_password认证插件,虽然user表结构有所变化,但权限字段名仍然兼容。
推荐直接用下面这个语句,适配MySQL 5.7和8.0+:
SELECT User, Host, authentication_string FROM mysql.user WHERE Select_priv = 'Y' AND Insert_priv = 'Y' AND Update_priv = 'Y' AND Delete_priv = 'Y' AND Create_priv = 'Y' AND Drop_priv = 'Y' AND Reload_priv = 'Y' AND Shutdown_priv = 'Y' AND Process_priv = 'Y' AND File_priv = 'Y' AND Grant_priv = 'Y' AND References_priv = 'Y' AND Index_priv = 'Y' AND Alter_priv = 'Y' AND Show_db_priv = 'Y' AND Super_priv = 'Y' AND Create_tmp_table_priv = 'Y' AND Lock_tables_priv = 'Y' AND Execute_priv = 'Y' AND Repl_sla ve_priv = 'Y' AND Repl_client_priv = 'Y';
需要强调的是,此方法仅适用于查询全局权限。如果要查找数据库级别的ALL权限用户,则不应使用mysql.user表,因为库/表级别的权限信息存储在mysql.db和mysql.tables_priv等表中,需要进行联合查询。
用 SHOW GRANTS 批量验证更可靠
SHOW GRANTS FOR 'user'@'host' 命令是最可靠的验证方式。它能够展示用户当前生效的所有权限集合,包括全局、数据库、表和列级别的权限,并以可读的SQL语句格式输出。唯一的不足是无法在一条SQL中查询所有用户,需要编写脚本或使用循环逐个执行。
手动检查高危账号时,可以用以下技巧生成命令:
SELECT CONCAT('SHOW GRANTS FOR ''', User, '''@''', Host, ''';') AS cmd
FROM mysql.user
WHERE Super_priv = 'Y' OR Create_user_priv = 'Y' OR Grant_priv = 'Y';
将结果中的命令复制出来,逐条执行。这种方法的优势在于,它比直接检查29个字段更接近真实的授权状态。特别是当用户同时拥有GRANT OPTION,或者曾被REVOKE部分权限时,字段值可能滞后于实际效果。
有几个常见的误判点值得留意:
GRANT ALL ON *.*的用户在mysql.user表中对应字段自然是全'Y',但如果是GRANT ALL ON mydb.*,则mysql.user表不会改变,权限仅写入mysql.db表。- MySQL 8.0+引入了角色系统,用户权限可能来自角色继承。此时
mysql.user中的字段可能仍为'N',但SHOW GRANTS会如实显示角色授予的权限。 - 执行
FLUSH PRIVILEGES后权限才正式生效。在刷新之前,mysql.user表虽然已更新,但内存缓存尚未同步,SHOW GRANTS可能仍显示旧状态。
为什么不能只看 Super_priv = 'Y' 就认为是 ALL
Super_priv确实是超级用户权限,拥有它可以执行KILL、SET GLOBAL、修改全局变量等操作。但它并不会自动赋予SELECT、INSERT等基础数据操作权限。试想,如果一个用户只有Super_priv = 'Y',其他权限均为'N',那么连SELECT * FROM mysql.user都会被拒绝。
反过来,GRANT ALL PRIVILEGES ON *.*在MySQL 5.7+中确实会将Super_priv设置为'Y',但这一逻辑不能逆推。仅凭Super_priv判断,一方面可能会遗漏那些非超级但权限全开的账号(尽管极少见),另一方面也可能误报仅用于运维的超级账号。
要真正定位“什么都能做”的用户,必须确认其拥有完整的数据操作、结构变更和管理类权限组合,且作用域为*.*。最稳妥的方法是:先通过字段查询进行初步筛选,再使用SHOW GRANTS对结果逐一确认,尤其要检查WITH GRANT OPTION是否存在——因为这才是权限扩散的真正开关。
