要查出谁有某个数据库的权限,需联合查询 mysql.db(库级权限)和 mysql.user(全局权限),因 MySQL 权限分层叠加且缓存需 FLUSH PRIVILEGES 生效。

如何查出谁有某个数据库的权限
MySQL 本身没有“数据库拥有者”这个概念(不像 PostgreSQL 有 pg_database.datdba),所谓“拥有者”实际是**对某库具备全部或关键操作权限的用户**。要定位这类用户,不能只看 mysql.user 表,必须结合权限层级逐层查。
-
SHOW GRANTS FOR '用户名'@'host'是最直接的方式,但前提是你得知道用户名——而你往往不知道 - 更实用的做法是反向查:从
mysql.db表里筛选出对目标数据库(比如myapp)有非空权限字段的记录:SELECT user, host, select_priv, insert_priv, update_priv, delete_priv, create_priv, drop_priv FROM mysql.db WHERE db = 'myapp' AND (select_priv = 'Y' OR insert_priv = 'Y' OR update_priv = 'Y' OR delete_priv = 'Y');
- 注意:
mysql.db只存数据库级权限;如果用户是通过全局权限(mysql.user中的Select_priv='Y')间接获得访问权,这条记录不会出现在mysql.db里——得额外查mysql.user中user和host非空且对应权限为'Y'的行
为什么 SELECT * FROM mysql.user WHERE user='xxx' 不够用
因为 MySQL 权限是分层叠加的:全局 → 数据库 → 表 → 列 → 存储过程。只查 mysql.user 只能看到用户是否被授予了“所有库”的权限(如 Super_priv、Grant_priv),但无法反映其在具体数据库上的实际能力。
- 例如,
root@localhost在mysql.user中select_priv='Y',说明它有全局 SELECT 权限,自然能查任意库——但它在mysql.db中可能根本没记录 - 而一个普通用户
appuser@'10.20.%'可能在mysql.db中有db='myapp'且select_priv='Y',但在mysql.user中所有权限字段都是'N' - 所以必须联合查:
mysql.user(全局权限)、mysql.db(库级权限)、必要时再加mysql.tables_priv(表级)
mysql.db 表结构和关键字段含义
mysql.db 是存储数据库级权限的核心系统表,它的结构决定了你能查到什么。执行 DESCRIBE mysql.db; 可看到字段,重点留意以下几列:
-
Host和User:权限绑定的客户端来源,不是“登录名”而是“谁+从哪来”,比如'appuser'@'192.168.1.%' -
Db:数据库名(区分大小写,取决于系统变量lower_case_table_names) -
Select_priv到Grant_priv:每个都是'Y'或'N',代表是否授权该操作;'Y'才算真正有权限,NULL或空字符串等同于'N' - 别误读
Grant_priv:它表示该用户能否把当前库的权限再转授他人,和“是否有权访问”无关
容易踩的坑:权限未生效 / 查不到人
即使你在 mysql.db 里改了权限,或者刚执行了 GRANT,也常出现“查得到记录但连不上库”或“SHOW GRANTS 显示没权限”——这不是查法错,是 MySQL 的权限缓存机制在作怪。
- 修改
mysql.db或mysql.user后,**必须执行FLUSH PRIVILEGES;**,否则变更仅存于内存缓存,不落地也不生效 -
GRANT语句会自动刷新权限,但直改系统表不会——这是最常被忽略的一步 - 如果用户连接时用了错误的
host(比如授权的是'user'@'10.%',但客户端解析出的 IP 是'user'@'10.0.0.100'而 DNS 反查失败变成'user'@'host123'),权限匹配失败,查mysql.db也找不到对应行 - MySQL 8.0+ 默认启用
caching_sha2_password认证插件,旧客户端可能连不上——这和权限无关,但现象类似,别混为一谈
权限层级多、缓存机制隐式、host 匹配敏感——查“谁有某库权限”这事,本质是在做一次小型权限溯源,不能只盯一张表。


















