必须先执行revoke all privileges on . from 'app_user'@'172.16.0.%'清空所有权限,再显式授予业务库权限;系统库不可授权,需查mysql.db表验证隔离效果,并通过连接参数、错误脱敏等应用层措施实现真正隔离。

直接禁用系统库访问必须先收回全局权限
新建或改造应用账号时,REVOKE ALL PRIVILEGES ON *.* FROM 'app_user'@'172.16.0.%' 这一步不能跳过。MySQL 权限是叠加的,哪怕之前只执行过一次 GRANT SELECT ON *.*,后续单独对业务库授权也无法覆盖——系统库(mysql、performance_schema、information_schema)依然可读。这步操作清空所有隐式继承或历史残留权限,让授权从零开始。
显式授权时绝对不要提系统库名
只要 GRANT 语句里没出现 mysql、performance_schema、information_schema,MySQL 就不会给任何访问路径。系统库不支持表级授权,也不该被授任何权限。
- ✅ 正确:
GRANT SELECT, INSERT ON app_db.orders TO 'app_user'@'172.16.0.%' - ❌ 错误:
GRANT SELECT ON mysql.user TO 'app_user'@'%'(语法通过但绝不能执行) - ⚠️ 隐患:
GRANT SELECT ON app_db.* TO 'app_user'@'%'后未检查是否误授了通配匹配的系统库名(如mysql_backup)
验证是否真被隔离:查 mysql.db 表而非只看 SHOW GRANTS
SHOW GRANTS FOR 'app_user'@'172.16.0.%' 只显示显式授予的语句,不反映权限叠加结果。真正生效的库级权限记录在 mysql.db 表中,必须用 root 执行:
SELECT User, Host, Db FROM mysql.db WHERE User = 'app_user' AND Db IN ('mysql', 'performance_schema', 'information_schema');
如果有返回行,说明系统库已被意外授权,立刻 REVOKE SELECT ON mysql.* FROM 'app_user'@'172.16.0.%' 并 FLUSH PRIVILEGES。
INFORMATION_SCHEMA 无法靠权限关闭,得靠应用层收敛
即使用户对所有系统库都无显式权限,SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA 仍可能返回全部库名——这是 MySQL 8.0+ 的默认行为,不受 GRANT/REVOKE 控制。
- 唯一可控点:应用连接时强制指定
database=app_db参数,避免用户接触库列表逻辑 - 绝不授
USAGE ON *.*,否则等于开放所有库名可见性 - 若必须保留元数据查询能力,用视图封装敏感字段,或在代理层拦截
INFORMATION_SCHEMA查询
最易被忽略的是错误信息脱敏:用户执行 USE hidden_db 报错时,原样返回 Access denied for database 'hidden_db' 就等于主动泄露库名。真正的隔离,始于权限配置,止于错误响应的一致性处理。











