show databases仅显示用户有权限的数据库,因该语句受mysql.user.show_db_priv字段控制:值为'n'时按实际授权过滤库名,值为'y'则显示全部;revoke select不影响其行为,因select权限与库名可见性无关。

关掉 show_db_priv 字段并显式授库权限,才能让普通用户执行 SHOW DATABASES 时只看到自己能用的库名;只撤 SELECT 或改 information_schema 权限完全无效。
为什么 REVOKE SELECT ON *.* 不影响 SHOW DATABASES?
SELECT 权限控制的是“读某张表的数据”,和“列出数据库名”毫无关系。MySQL 的 SHOW DATABASES 可见性由 mysql.user.show_db_priv 字段决定,它是个独立的全局开关,值为 'Y' 就显示全部库名,'N' 才按实际授权过滤。
常见误操作包括:
- 执行
REVOKE SELECT ON information_schema.*—— 这只会阻止查INFORMATION_SCHEMA.SCHEMATA,但SHOW DATABASES仍返回全量库名 - 用
GRANT ALL ON *.*后再部分回收 —— 只要show_db_priv = 'Y',且存在任意全局匹配项(比如USAGE ON *.*),就仍会显示所有库 - 没指定
host精确匹配,导致UPDATE mysql.user改错了行(例如用户连的是'app'@'10.20.30.40',你却只改了'app'@'%')
真正生效的两步操作
必须同时完成以下两个动作,缺一不可:
- 把目标用户的
show_db_priv设为'N':UPDATE mysql.user SET show_db_priv = 'N' WHERE user = 'app_user' AND host = '%';
- 显式授予其目标库权限(哪怕只是
USAGE):GRANT USAGE ON `myapp_db`.* TO 'app_user'@'%';
注意:不能只靠CREATE USER,必须走GRANT写入授权表 - 刷新权限:
FLUSH PRIVILEGES;
用户重连后,SHOW DATABASES 就只返回 myapp_db、information_schema、performance_schema(系统库始终可见)。
MySQL 8.0.29+ 的新变量要注意
8.0.29 起引入了 show_database_privilege 系统变量,可替代 show_db_priv 字段,但默认不启用。如果你启用了它,就得用 SET PERSIST show_database_privilege = OFF;,而不是改 mysql.user 表。检查方式:
SELECT @@global.show_database_privilege;如果返回
ON,优先走变量控制;否则仍看 show_db_priv 字段。最容易被忽略的是:用户一旦被授予过 USAGE ON *.*,哪怕后续 revoke 了,只要 show_db_priv = 'Y',库名就全量可见——这个状态不会自动回滚,必须手动 update + flush。











