普通用户执行 show databases 仍能看到库名是因为拥有 show_db_priv 权限或可通过 information_schema.schemata 查询;需撤销该权限、配置 skip-show-database 并严格限制应用层库名访问。

普通用户执行 SHOW DATABASES 仍能看到库?先确认 Show_db_priv 是否被授予
MySQL 默认允许用户看到所有数据库名,只要该用户拥有 Show_db_priv 权限(即全局权限表 mysql.user 中对应字段为 Y)。这不是“显示隐藏库”的问题,而是权限没关干净。
检查方法:
用 root 登录后执行:
SELECT User, Host, Show_db_priv FROM mysql.user WHERE User = 'your_user';
如果返回 Y,说明该用户能执行 SHOW DATABASES —— 即使它对某个库没有任何操作权限,也能在列表里看到库名。
撤销方式(必须用 root 或高权限账号):
REVOKE SHOW DATABASES ON *.* FROM 'your_user'@'host';- 然后务必执行
FLUSH PRIVILEGES;生效
只禁用 SHOW DATABASES 还不够:INFORMATION_SCHEMA 仍是泄露源
即使用户无法执行 SHOW DATABASES,只要它能连上 MySQL,就可能通过查询 INFORMATION_SCHEMA.SCHEMATA 看到所有库名:
SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA;
这个行为不受 SHOW DATABASES 权限控制,而是由用户是否能访问 INFORMATION_SCHEMA 决定。MySQL 8.0+ 默认允许所有认证用户读取该库(只读),这是设计使然。
真正有效的限制手段只有两个:
- 在
my.cnf的[mysqld]段添加skip-show-database(影响所有非 SUPER 用户的SHOW DATABASES行为,但不阻止INFORMATION_SCHEMA查询) - 更彻底的做法:用应用层连接时直接指定
database=xxx参数,让用户从不接触库列表;同时确保其权限仅落在具体库/表上,不授USAGE ON *.*
为什么 REVOKE ALL ON hidden_db.* 后用户仍可能“猜出”库存在
撤销权限只是让 USE hidden_db 或 SELECT FROM hidden_db.table 报错,但不会抹除库名可见性。常见误判场景:
- 用户尝试
USE hidden_db→ 报错Access denied for user ... to database 'hidden_db',这等于直接暴露了库名 - 应用日志或错误页面未脱敏,把这类报错原样打出来,等于主动泄露
- 某些 ORM 或管理工具(如早期 phpMyAdmin)会主动探测库是否存在,靠响应时间或错误码差异做枚举
所以“隐藏”的关键不是让它不可查,而是让它不可推断 —— 错误信息统一成 Invalid operation,连接池固定绑定库名,前端不传任何动态库名参数。
最简可行方案:root 配置 + 应用连接约束
不需要改源码、不依赖插件,三步落地:
- 在
my.cnf加skip-show-database并重启 MySQL(影响所有非 SUPER 用户的SHOW DATABASES) - 创建应用专用用户,只授具体库权限,例如:
GRANT SELECT,INSERT ON app_prod.* TO 'app_user'@'%';,**不执行GRANT USAGE ON *.*** - 应用连接字符串中强制指定
database=app_prod,代码里禁止拼接库名,所有 SQL 去掉前缀(如写SELECT * FROM users而非SELECT * FROM app_prod.users)
此时普通用户登录后执行 SHOW DATABASES 只能看到自己有权限的库(甚至一个都看不到,取决于是否授了 USAGE),而 INFORMATION_SCHEMA.SCHEMATA 查询虽仍可执行,但因无权访问其他库的元数据,多数字段(如 DEFAULT_COLLATION_NAME)返回 NULL,实际价值极低。
真正的难点不在配置,而在守住应用层那条线:任何把数据库结构反射到前端、日志、API 响应的地方,都会让所有权限设置失效。











