必须将mysql.user表中show_db_priv设为'n'并显式授予目标库usage权限,才能使show databases仅显示用户有权限的数据库;该语句不受select等常规权限控制,且information_schema.schemata仍可被查询。

SHOW DATABASES 不受 GRANT/REVOKE 控制
撤销 SELECT、INSERT 等权限后,用户仍能执行 SHOW DATABASES 并看到全部库名,是因为这个语句的可见性根本不由常规权限控制。它只取决于 mysql.user.show_db_priv 字段值:为 'Y' 时全量显示,为 'N' 才按实际授权过滤。
常见误操作包括:
- 执行
REVOKE SELECT ON *.* FROM 'u'@'%'—— 完全无效,SELECT权限管的是读表数据,不是列库名 - 修改
information_schema权限(如REVOKE SELECT ON information_schema.*)—— 也不影响SHOW DATABASES,只会影响后续手动查SCHEMATA - 用
GRANT ALL ON *.*后再部分回收 —— 只要show_db_priv = 'Y'且存在任意全局匹配项(比如USAGE ON *.*),就仍显示所有库
真正生效的两步必须同时做
只改一个地方,SHOW DATABASES 的行为就不会变。必须同步完成:
UPDATE mysql.user SET show_db_priv = 'N' WHERE user = 'u' AND host = '%';-
GRANT USAGE ON `target_db`.* TO 'u'@'%';(哪怕只给USAGE,也满足“有权限才可见”) - 执行
FLUSH PRIVILEGES;
注意:不能只靠 CREATE USER,必须走 GRANT 写入授权表;主机名必须精确匹配,否则可能改错行(比如用户连的是 'u'@'10.20.30.40',你却只更新了 'u'@'%')。
MySQL 8.0.29+ 引入了新变量
如果你用的是 8.0.29 或更高版本,得先检查是否启用了新机制:
SELECT @@global.show_database_privilege;
如果返回 ON,说明系统正在用变量控制,而不是读 mysql.user.show_db_priv。此时应:
SET PERSIST show_database_privilege = OFF;- 重启 mysqld 或执行
FLUSH PRIVILEGES;(视版本而定)
旧版本或变量为 OFF 时,仍以 show_db_priv 字段为准。
INFORMATION_SCHEMA 是另一个泄露源
即使关掉了 SHOW DATABASES,用户仍可能通过以下方式看到所有库名:
SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA;
这个查询不受 show_db_priv 控制,只取决于用户能否访问 INFORMATION_SCHEMA。MySQL 默认允许所有已认证用户访问该库,所以:
- 仅靠关
show_db_priv无法完全隐藏库名 - 若需彻底隔离,得配合应用层限制、网络层 ACL,或使用 MySQL Router / Proxy 做透明拦截
- 不要试图靠
REVOKE SELECT ON information_schema.*来堵——它只会让这条 SQL 报错,但其他绕过方式(如连接时指定库名再查TABLES)依然存在
最常被忽略的是:一旦用户被授予过 USAGE ON *.*,哪怕后来 revoke 了,只要 show_db_priv = 'Y',库名就全量可见——这个状态不会自动回滚,必须手动 update + flush。











