mysql 8.0.12+可直接revoke select on information_schema.生效,5.7及更早版本不支持该语法,须先revoke all privileges on .*再严格授予业务库权限,并配合skip-show-databases禁用show databases以阻断元数据探测链。

禁用 MySQL 用户对 information_schema 的访问权限,核心取决于版本:MySQL 8.0.12+ 可直接 REVOKE SELECT ON information_schema.*,5.7 及更早版本不支持该语法,必须靠清空全局权限 + 严格授业务库权限来间接限制。
MySQL 8.0.12+:直接撤权有效,但需匹配原始授权范围
该版本起,REVOKE SELECT ON information_schema.* FROM 'user'@'%' 是真正生效的操作,执行后用户无法查询 INFORMATION_SCHEMA.TABLES、INFORMATION_SCHEMA.COLUMNS 等视图。
- 先确认版本:
SELECT VERSION();,避免在低版本误执行报错ERROR 1044 - 检查当前授权:
SHOW GRANTS FOR 'user'@'%';,若存在GRANT SELECT ON *.*,必须先REVOKE SELECT ON *.* FROM 'user'@'%'—— 否则REVOKE SELECT ON information_schema.*会被忽略 - 执行撤权后无需
FLUSH PRIVILEGES,GRANT/REVOKE 操作即时生效 - 撤权后仍能查到自己业务库的表名?正常——只要用户有
app_db的SELECT权限,SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'app_db'依然合法且可执行
MySQL 5.7 及更早:REVOKE 无效,只能靠权限隔离
这些版本根本不支持对 information_schema 显式授权或回收,REVOKE SELECT ON information_schema.* 会直接报错。唯一可行路径是切断用户“能访问任意库”的前提。
- 先清空历史权限:
REVOKE ALL PRIVILEGES ON *.* FROM 'user'@'%'; - 再只授予具体业务库权限,例如:
GRANT SELECT ON app_db.* TO 'user'@'%';—— 不写*或*.*,否则等于放行全部 - 确保没漏掉
mysql或performance_schema:SELECT User, Host, Db FROM mysql.db WHERE Db IN ('mysql', 'performance_schema', 'information_schema');,若有结果立刻REVOKE或DROP USER - 用户仍能看到
information_schema出现在SHOW DATABASES结果里?这是系统强制可见,但无法查其内容 —— 只要没给任何 SELECT 权限,SELECT * FROM information_schema.TABLES会报ERROR 1142
为什么关了 information_schema 还能看到库名?因为 SHOW DATABASES 不依赖它
SHOW DATABASES 的可见性由 mysql.user.show_db_priv 字段和用户是否拥有任意数据库的 USAGE 或更高权限共同决定,跟 information_schema 完全无关。
- 设
show_db_priv = 'N'(UPDATE mysql.user SET show_db_priv = 'N' WHERE user = 'user' AND host = '%';),再执行FLUSH PRIVILEGES;,用户就只能看到自己被显式GRANT过的库 - 或者启用
skip-show-databases:在my.cnf的[mysqld]段加这一行,然后重启 MySQL —— 非 SUPER 用户执行SHOW DATABASES将返回空结果集 - 注意:
skip-show-databases对 root 或有 SUPER 权限的用户无效,务必确认应用账号没被授予WITH GRANT OPTION或SUPER
GRANT USAGE ON *.* 是安全起点,不是摆设
新建用户后,别急着授业务权限。先执行 GRANT USAGE ON *.* TO 'user'@'%';,这会让用户能连上但啥都干不了 —— 是唯一安全的“占位符”操作。
- 它不赋予任何数据库操作能力,只允许认证通过
- 后续
GRANT SELECT ON app_db.*是叠加在其上的,不会意外继承全局权限 - 跳过这步直接
GRANT SELECT ON app_db.users,MySQL 8.0+ 会报ERROR 1410(用户未预创建) - 很多权限残留问题,根源就是脚本里漏了
GRANT USAGE或没做前置REVOKE ALL
真正难的不是怎么写那条 REVOKE 语句,而是理清权限叠加逻辑、host 匹配精度、以及 SHOW DATABASES 和 INFORMATION_SCHEMA 之间根本不同的控制机制 —— 这三者混在一起,一个配置不对,元数据就又漏出去了。











