查权限应直接查询系统表:全局权限查mysql.user,数据库级查mysql.db,表级查mysql.tables_priv;权限校验按user→db→tables_priv→columns_priv顺序叠加,前层'y'覆盖后层,'n'则继续向下检查。

查某个权限(如SELECT)被授予了哪些用户
直接查 mysql.user 或 mysql.db 表里的权限字段,比倒推 SHOW GRANTS 输出更可靠。因为 SHOW GRANTS 只返回显式授权语句,而系统表字段是 MySQL 实际校验时读取的原始值。
全局 SELECT 权限:看 mysql.user 中 Select_priv = 'Y' 的记录
SELECT User, Host FROM mysql.user WHERE Select_priv = 'Y';- 注意:
Select_priv为'Y'表示该用户对所有数据库都有 SELECT 权限,不是“有任意一个库的 SELECT” - 如果只在某库有 SELECT(比如
GRANT SELECT ON app.*),这条记录不会出现在mysql.user里,得去mysql.db
查数据库级权限(如对 orders 库的 INSERT)
数据库级权限不存 mysql.user,必须查 mysql.db,且要同时匹配 User、Host 和 Db 字段。
SELECT User, Host, Db, Insert_priv FROM mysql.db WHERE Insert_priv = 'Y' AND Db = 'orders';- 结果中的
User和Host是完整账号标识,例如'app_user'@'10.20.%'—— 这个组合才是实际生效的用户 -
mysql.db里Insert_priv为'Y',只代表对Db列指定的库下所有表有 INSERT 权限,不包含表级或列级例外
查表级权限(如对 logs 表的 UPDATE)
表级权限极少用,但一旦存在,就只在 mysql.tables_priv 里体现,mysql.user 和 mysql.db 都查不到。
SELECT User, Host, Db, Table_name, Table_priv FROM mysql.tables_priv WHERE FIND_IN_SET('Update', Table_priv) > 0 AND Db = 'myapp' AND Table_name = 'logs';-
Table_priv是逗号分隔字符串(如'Select,Update'),不能用=直接匹配,得用FIND_IN_SET - 注意:即使
mysql.db里Update_priv = 'N',只要mysql.tables_priv里有对应记录,UPDATE 就能执行
容易忽略的权限叠加和覆盖逻辑
MySQL 检查权限时按 user → db → tables_priv → columns_priv 顺序逐层细化,前面层级的 'N' 不会阻止后面层级的权限生效;但前面是 'Y',后面同名权限就不再检查。
- 一个用户在
mysql.user中Select_priv = 'Y',那他对所有库的 SELECT 都通过,mysql.db里哪怕写Select_priv = 'N'也无效 - 但如果
mysql.user是'N',MySQL 就继续查mysql.db;如果那里也是'N',再查mysql.tables_priv - 这意味着:你查到某用户在
mysql.db有Insert_priv = 'Y',不代表他一定能 INSERT——得确认mysql.user对应字段不是'Y'(否则说明是全局权限),也不是'N'(否则说明没权限)











