mysql权限管控需严格指定数据库名、host和权限范围:grant必须写为on app_production.*;host须精确匹配如'10.0.0.%';旧全局权限需revoke后再重授;information_schema默认可见但数据受限,可额外revoke其select权限。

GRANT 时漏写数据库名会导致权限失控
MySQL 不会默认把用户绑定到某个 Schema,GRANT SELECT ON * 或 GRANT SELECT ON *.* 这类写法等于放行全部库——哪怕你只打算让第三方查 app_production。真正起作用的必须是带具体库名的语法:GRANT SELECT ON app_production.*。否则用户连上后执行 SHOW DATABASES 可能仍看到其他库名(虽无法访问),更严重的是 ORM 自动加前缀如 other_db.users 时,只要权限含 *.* 就能绕过隔离。
host 匹配不精确会让 GRANT 形同虚设
常见错误是建用户时用 'thirdparty'@'%',但第三方实际连接 IP 是 10.0.0.5:33060(带端口)或 IPv6 地址。MySQL 8.0+ 默认禁用 % 匹配这类地址,导致 CURRENT_USER() 返回 'thirdparty'@'10.0.0.5',而你授的权限在 'thirdparty'@'%' 下根本不会生效。
- 验证方式:用第三方环境连上后执行
SELECT CURRENT_USER(), USER(); - 稳妥做法:明确指定 host,比如
'thirdparty'@'10.0.0.%'或'thirdparty'@'192.168.10.0/255.255.255.0' - 若走 NAT/代理,需确认出口 IP 并按真实地址授权
GRANT 后不检查权限残留,旧权限可能覆盖新设置
如果该用户之前被授予过 GRANT SELECT ON *.* 或 GRANT USAGE ON *.*,后续再执行 GRANT SELECT ON app_production.* 不会自动撤销旧权限。结果就是:你以为锁死了,其实用户还能查 mysql.user 或触发 INFORMATION_SCHEMA.TABLES 扫描。
- 先运行
SHOW GRANTS FOR 'thirdparty'@'10.0.0.5';确认当前所有权限 - 若有全局权限,必须显式回收:
REVOKE ALL PRIVILEGES ON *.* FROM 'thirdparty'@'10.0.0.5'; - 再重新授业务库权限:
GRANT SELECT ON app_production.* TO 'thirdparty'@'10.0.0.5'; -
FLUSH PRIVILEGES;在常规 GRANT 场景下非必需,但回收+重授组合后建议执行一次以防缓存延迟
information_schema 默认可见,但内容受权限约束
用户即使只有 app_production 的 SELECT 权限,SHOW DATABASES 仍会列出 information_schema(系统强制可见),但这不意味着能查里面的数据。不过只要他有任意一张表的 SELECT 权,就能执行 SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'app_production'——这是合法行为,不是漏洞。
- 如需进一步限制元数据暴露,MySQL 8.0.12+ 支持:
REVOKE SELECT ON `INFORMATION_SCHEMA`.* FROM 'thirdparty'@'10.0.0.5'; - 注意:这不会影响
SHOW TABLES或DESCRIBE,只限制直接查INFORMATION_SCHEMA表 - 别碰
performance_schema和mysql库,应用账号不该有任何访问权限
权限模型本身不提供“默认拒绝其他库”的快捷开关,每一步都得手动对齐目标 Schema、host、权限粒度。最容易被忽略的是:建完用户后没立刻 REVOKE 全局权限,导致后续 GRANT 覆盖不干净。











