必须将目标用户的show_db_priv设为'n'并显式授予业务库usage权限,否则show databases仍显示全部库名;常见失效原因是host不匹配、残留全局usage权限、或mysql 8.0.29+启用了show_database_privilege变量。

必须将目标用户的Show_db_priv字段设为'N',并显式授予其业务库权限(哪怕只有USAGE),否则SHOW DATABASES仍会返回全部库名。
为什么REVOKE SHOW DATABASES ON *.*有时不生效
常见错误是没匹配到正确的User和Host组合。MySQL 把'user'@'localhost'和'user'@'%'视为两个独立账号,用错Host会导致UPDATE或REVOKE操作完全作用在错误账户上。
- 先确认实际连接来源:
SELECT User, Host FROM mysql.user WHERE User = 'app_user'; - 执行撤权时必须写全:
REVOKE SHOW DATABASES ON *.* FROM 'app_user'@'10.20.30.40';,不能只写@'%'假设覆盖所有 - 如果用户已存在且曾被授过
GRANT ALL ON *.*,仅REVOKE SHOW DATABASES不够——残留的全局USAGE仍可能触发隐式可见性,得配合UPDATE mysql.user SET Show_db_priv = 'N' WHERE User = 'app_user' AND Host = '10.20.30.40'; - 执行后务必
FLUSH PRIVILEGES;,尤其在直接改表后
禁用后仍能看到库名?检查INFORMATION_SCHEMA是否被绕过
SHOW DATABASES权限关闭后,用户仍可能执行SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA;查出所有库名——这不是漏洞,而是 MySQL 8.0+ 的默认行为:只要认证成功,默认允许读INFORMATION_SCHEMA。
- MySQL 8.0.12+ 可用:
REVOKE SELECT ON information_schema.* FROM 'app_user'@'10.20.30.40';,但前提是该用户此前没被授过SELECT ON *.*,否则撤权无效 - 若版本低于 8.0.12,无法显式回收
information_schema权限,唯一办法是先REVOKE ALL PRIVILEGES ON *.*,再只授GRANT SELECT ON app_db.* - 注意:
performance_schema和sys库对所有已认证用户始终可见,无法隐藏
MySQL 8.0.29+ 要额外留意show_database_privilege变量
这个系统变量一旦启用,就会覆盖mysql.user.Show_db_priv字段的行为,导致前面所有UPDATE或REVOKE操作失效。
- 检查是否启用:
SELECT @@global.show_database_privilege;,返回ON即表示它在起作用 - 若启用,应改用:
SET PERSIST show_database_privilege = OFF;(需有SYSTEM_VARIABLES_ADMIN权限) - 该变量默认是
OFF,但某些云托管服务或自动化部署脚本可能悄悄开启它 - 即使变量关闭,也必须确保
mysql.user.Show_db_priv = 'N',两者是“或”关系:任一为真,SHOW DATABASES就显示全量
最易被忽略的是:只要用户被授予过任何数据库的USAGE权限(哪怕是GRANT USAGE ON hidden_db.*),且Show_db_priv = 'Y',库名就全量可见——这个状态不会因后续REVOKE自动回滚,必须手动UPDATE字段并FLUSH。











