真正控制库名可见性的是show_db_priv权限而非select权限;需将mysql.user表中对应用户的show_db_priv设为'n'并执行flush privileges,用户重连后show databases仅显示其被显式授权(含usage)的数据库。

SELECT 权限本身不是全局开关,关不掉——真正控制“能看到哪些库名”的,是 show_databases 权限(对应 mysql.user.show_db_priv 字段),不是 SELECT。
为什么关 SELECT 权限对隐藏库名完全无效
-
SELECT控制的是“能否读取某张表的数据”,和“能否列出数据库名”毫无关系; - 即使用户对所有库、所有表都只有
USAGE(零操作权限),只要show_db_priv = 'Y',执行SHOW DATABASES仍会返回全部库名; - 同理,撤销
SELECT ON <em>.</em>或REVOKE SELECT ON mysql.*都不会影响库列表可见性; - 常见误操作:用
REVOKE SELECT ON information_schema.*试图隐藏库名——这只能阻止查INFORMATION_SCHEMA.SCHEMATA,但SHOW DATABASES仍照常工作。
怎么真正让普通用户只看到自己能用的库
- 直接把目标用户的
show_db_priv设为'N':UPDATE mysql.user SET show_db_priv = 'N' WHERE user = 'app_user' AND host = '%';
- 然后必须执行:
FLUSH PRIVILEGES;
- 用户重连后,
SHOW DATABASES就只会显示那些它被显式授过权的库(哪怕只是GRANT USAGE ON db1.*); - 注意:如果之前给过
GRANT ALL ON <em>.</em>,得先REVOKE ALL ON <em>.</em>,否则该用户仍满足“有权限”条件,库名照常可见。
关了 show_db_priv 还能看到库名?检查这几个点
- 用户是否被授予了
USAGE ON <em>. </em>?这个通配授权会让它“名义上有权访问所有库”,从而触发全量可见; - 是否漏掉了某个
host段?比如用户实际连的是'app_user'@'10.20.30.40',但你只改了'app_user'@'%'; - MySQL 版本是否 ≥ 8.0.29?该版本起支持
show_database_privilege系统变量,可替代show_db_priv字段,但默认不启用; - 应用是否在连接字符串里硬写了
database=xxx?这种情况下,用户根本不需要看库列表,也就不暴露问题——这才是更稳妥的实践。
show_db_priv 是个一锤定音的开关,但它只在连接建立时读取一次;改完不 FLUSH PRIVILEGES,或用户不重连,就等于没改。











