必须将mysql.user表中show_db_priv设为'n'才能禁用show databases权限,此时用户仅见其被显式授过权(含usage)的数据库;information_schema.schemata仍可被查询,需应用层指定database参数并严格限制权限粒度。

直接禁用 SHOW DATABASES 权限才有效
普通用户执行 SHOW DATABASES 仍能看到所有库名,根本原因不是前端没过滤,而是其账号在 mysql.user 表里的 Show_db_priv 字段为 'Y'。这个字段是全局开关,设为 'N' 后,该用户执行 SHOW DATABASES 就只会列出自己被显式授过权(哪怕只有 USAGE)的库,其余全部不显示。
别指望靠 REVOKE SELECT ON hidden_db.* 或删权限来“隐藏库名”——那只是让 USE hidden_db 报错,库名依然可见。
-
REVOKE SHOW DATABASES ON *.* FROM 'user'@'host';是最安全的写法,必须带ON *.* - 如果用户已存在且权限复杂,优先用
UPDATE mysql.user SET Show_db_priv='N' WHERE User='user' AND Host='host'; FLUSH PRIVILEGES;,避免GRANT/REVOKE语句误触发隐式权限重置 - 检查是否生效:用 root 执行
SELECT User, Host, Show_db_priv FROM mysql.user WHERE User='user';,确认值为N
INFORMATION_SCHEMA.SCHEMATA 仍是泄露源
即使关掉 SHOW DATABASES 权限,只要用户能连上 MySQL,就可能执行 SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA; 查出所有库名。MySQL 8.0+ 默认允许所有认证用户读取 INFORMATION_SCHEMA,这是设计行为,不受权限位控制。
真正可控的只有两个点:
- 应用层连接时强制指定
database=xxx参数,让用户从不接触库列表逻辑 - 严格限制账号权限粒度:只给
GRANT SELECT ON target_db.*或最低限度的GRANT USAGE ON target_db.*,绝不授ON *.* - 若必须保留查询能力,考虑用视图封装 + SQL rewrite(如代理层拦截
INFORMATION_SCHEMA查询),但原生 MySQL 不支持直接禁读该库
my.cnf 中的 skip-show-database 不解决核心问题
在 [mysqld] 段加 skip-show-database,只会影响未授权用户执行 SHOW DATABASES 时直接报错(ERROR 1227 (42000): Access denied),但对已拥有 Show_db_priv='Y' 的用户完全无效。它不改变 INFORMATION_SCHEMA.SCHEMATA 的可读性,也不影响 DBA 或监控脚本直连后的可见性。
这个配置适合快速堵住低权限账号的试探性扫描,但不能替代权限隔离策略。
- MySQL 8.0+ 默认已启用该选项,但仅作用于未授权用户
- 它和
SHOW DATABASES权限是正交机制:一个控制命令执行结果,一个控制元数据访问范围 - 不要把它当成“隐藏系统库”的手段——
mysql、sys、performance_schema等仍会在INFORMATION_SCHEMA.SCHEMATA中出现
系统库名无法真正隐藏,只能收缩可见范围
MySQL 没有“隐藏系统数据库”的原生能力。database_ignore=sys,performance_schema 这类配置并不存在于任何官方文档或 9.6.0 版本中,属于错误信息。重命名 performance_schema 或改权限表字段,会导致 MySQL 启动失败或功能异常,因为这些库被服务端硬编码依赖。
真正能做的只有两件事:
- 确保非 DBA 用户没有
SELECT权限访问mysql.user、mysql.db等敏感系统表 - 接受
information_schema和performance_schema对所有连接用户可见的事实,把防护重心放在业务库的权限隔离上 - 若审计要求极高,需配合 RLS 类中间件或数据库代理层做查询拦截,而非寄望于 MySQL 自身配置
最常被忽略的一点:用户即使看不到库名,只要知道库名(比如从日志、配置、旧备份中猜到),仍可直接 USE known_db 并触发权限校验——所以“看不见”不等于“不可达”,关键还是最小权限原则落地。











