根本原因是show databases权限未关闭,它依赖mysql.db等授权表而非information_schema;应设mysql.user.show_db_priv='n'并flush privileges,或配置skip-show-databases。

普通用户能看到其他库名,根本原因不是 INFORMATION_SCHEMA 没关好,而是 SHOW DATABASES 权限没关——这个权限控制的是“列出来”,不是“能不能查”。关掉它,再配合最小化授权,才能真正隐藏库名。
为什么关 INFORMATION_SCHEMA 权限没用
MySQL 的 SHOW DATABASES 命令不依赖 INFORMATION_SCHEMA。它读的是 mysql.db、mysql.tables_priv 等授权表,只要用户对某个库有哪怕 USAGE 权限,那个库就会出现在结果里。所以即使你执行了 REVOKE SELECT ON INFORMATION_SCHEMA.*,SHOW DATABASES 依然照常显示所有他“被授过权”的库。
常见错误现象:
- 在 MySQL 5.7 执行
REVOKE SELECT ON INFORMATION_SCHEMA.*→ 报错ERROR 1044,因为旧版本根本不支持该语法 - 在 MySQL 8.0+ 执行成功,但
SHOW DATABASES结果不变 → 因为可见性不由INFORMATION_SCHEMA控制
真正该关的是 show_db_priv 字段
这个字段在 mysql.user 表里,是布尔值,决定用户执行 SHOW DATABASES 时是否启用“只显示有权限的库”模式。设为 'N' 后,用户只能看到自己被显式 GRANT 过(哪怕只是 USAGE)的库。
实操步骤:
- 用 root 登录后执行:
UPDATE mysql.user SET show_db_priv = 'N' WHERE user = 'your_user' AND host = '%'; - 必须指定
host,避免误改多个同名用户 - 执行
FLUSH PRIVILEGES;—— 这步不能省,否则修改不生效 - 验证:
SELECT user, host, show_db_priv FROM mysql.user WHERE user = 'your_user';,确认返回'N'
关完之后,用户还是看不到自己的库?检查授权粒度
关掉 show_db_priv 只是开关,真正让库“出现”在 SHOW DATABASES 结果里的,是授权记录本身。MySQL 不看“能不能查数据”,只看“有没有对应授权行”。
以下操作会让库名出现在结果中:
GRANT SELECT ON mydb.* TO 'u'@'%';-
GRANT USAGE ON mydb.* TO 'u'@'%';(USAGE是占位权限,无实际能力但满足可见条件)
以下操作不会让库名出现:
- 只创建了用户,没对任何库执行
GRANT -
GRANT SELECT ON *.*→ 这会触发全局权限,导致show_db_priv失效,用户又看到全部库名
更彻底的方案:用 skip-show-databases
如果不想依赖用户级配置,或者需要统一策略,直接在 my.cnf 的 [mysqld] 段加一行:
skip-show-databases
重启 mysqld 后,所有非 SUPER 用户执行 SHOW DATABASES 都会返回空结果集。注意:
- root 或带
SUPER权限的账号不受影响,所以务必确保应用账号没被授予WITH GRANT OPTION或SUPER - 这个配置对
INFORMATION_SCHEMA.SCHEMATA查询无效,用户仍可通过SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA查到库名——所以仍需配合REVOKE SELECT ON INFORMATION_SCHEMA.*(MySQL 8.0.12+)
最易被忽略的一点:information_schema 和 performance_schema 默认对所有已认证用户可见,无法靠 GRANT 隐藏;而 skip-show-databases 又只影响 SHOW DATABASES 命令本身。真正的隔离必须同时处理这两层——命令可见性 + 元数据可查性。











