MySQL通过USER@Host组合精确控制客户端IP访问权限,Host支持通配符但不支持CIDR;权限匹配按Host精确度降序,冗余记录(如%@%)会阻断后续匹配;角色需显式绑定USER@Host并设为默认才生效。

怎么让某个客户端IP只能连指定数据库
MySQL的权限不是按“客户端程序”分,而是靠 USER@Host 这个组合来识别来源。你配的是 'appuser'@'192.168.1.100',那只有从这台机器用这个用户连,才会命中这条权限记录。
常见错误是只写 'appuser'@'%',结果任何IP都能连——哪怕你本意只想放行内网某台应用服务器。
- Host部分支持通配符:
'192.168.1.%'匹配整个C段,'%.example.com'匹配子域名,但不支持正则或CIDR写法 - 如果客户端走代理或NAT,看到的Host可能是代理IP,得按实际TCP连接源IP来配
- MySQL 8.0+ 默认启用
caching_sha2_password插件,旧客户端(如MySQL 5.7 client)连USER@Host权限正常的账号也可能报Authentication plugin 'caching_sha2_password' cannot be loaded,得显式指定插件或降级认证方式
GRANT语句里database名能不能用通配符
可以,但仅限于 GRANT ... ON db_name.* TO ... 这种形式,db_name 本身必须是真实存在的库名,不能写 myapp_%.* 或 `myapp\_%`.* ——MySQL不支持模式匹配库名。
想实现“一个账号能访问所有以 myapp_ 开头的库”,只能手动逐个GRANT,或者用脚本生成SQL。否则权限会静默失效,连 SHOW DATABASES 都看不到那些库。
-
GRANT SELECT ON `myapp_v1`.* TO 'reader'@'10.0.2.5';有效 -
GRANT SELECT ON `myapp_%`.* TO 'reader'@'10.0.2.5';语法通过,但实际不生效,查不到匹配库 - 如果库名含特殊字符(如短横线),必须用反引号包裹:
`myapp-prod`.*
为什么FLUSH PRIVILEGES后还是连不上
多数时候不是权限没刷,而是 USER@Host 没匹配上。MySQL在验证时会按 Host 精确度从高到低排序匹配:先找完全相同的IP,再找 192.168.1.%,最后才轮到 %。只要有一条更具体的记录存在,哪怕没赋权,也会阻断后续匹配。
典型现象:你刚加了 'api'@'10.0.3.10',但发现连不上,用 SELECT User,Host FROM mysql.user; 一看,底下还躺着一条 'api'@'%' 且 authentication_string 是空的(即密码为空),MySQL就优先选这条,而它没权限、也没密码校验逻辑,直接拒绝。
- 检查匹配顺序:
SELECT User,Host FROM mysql.user ORDER BY Host DESC;(注意%排最后,IP字面量排最前) - 删冗余记录:
DROP USER 'api'@'%';再重试 -
FLUSH PRIVILEGES只重载内存权限表,不影响正在运行的连接;新连接才会生效
MySQL 8.0+ 的角色机制怎么配合USER@Host用
角色本身不绑定Host,但授角色时可以限定范围。比如你建了个角色 app_reader,再用 GRANT app_reader TO 'svc'@'172.16.0.5';,这就把角色和特定客户端绑定了——不过要注意,角色权限仍需单独 GRANT ... ON db.* TO app_reader;,否则只是“有角色”但没实际权限。
容易忽略的是激活角色的时机:默认新用户不会自动激活角色,得显式执行 SET DEFAULT ROLE app_reader TO 'svc'@'172.16.0.5';,否则即使登录成功,SELECT 也会报 Access denied。
- 角色权限变更后,已登录用户需执行
SET ROLE app_reader;才能立即生效 - 不要对
'svc'@'%'授角色再指望它只在某IP生效——Host约束必须落在GRANT ... TO 'svc'@'ip'这一步 - 用
SHOW GRANTS FOR 'svc'@'172.16.0.5';能看到是否包含角色,以及角色是否被设为默认
真正卡住人的往往不是语法,而是MySQL按Host字面量做最长前缀匹配的隐式规则,以及角色和USER@Host这两层控制没叠对位置。










