mysql不支持cidr(如192.168.1.0/24),仅通过字符串前缀匹配模拟网段,如'192.168.1.%'本质是通配符行为,非网络层子网计算,会匹配非法ip且存在安全风险。

MySQL 不支持 CIDR(如 192.168.1.0/24),所谓“IP 段授权”只能靠字符串前缀匹配模拟,本质是通配符行为,不是网络层子网计算。直接写 GRANT ... TO 'u'@'192.168.1.0/24' 会报错或完全不生效。
为什么 192.168.1.% 能用但不是真子网控制
MySQL 的 Host 字段只认两个通配符:%(零个或多个任意字符)和 _(单个任意字符),不做 IP 地址解析。所以:
-
'user'@'192.168.1.%'匹配192.168.1.1、192.168.1.255,也匹配192.168.1.123abc(非法 IP 字符串) - 它不校验第四段是否在 0–255 范围内,也不拒绝
192.168.1.1000 -
'user'@'192.168.%'实际覆盖192.168.0.0到192.168.255.255,甚至192.168.x.y这类非数字结尾的字符串 - 写成
'192.168.1.*'或'192.168.1.0/24'都是语法错误或字面量匹配失败
GRANT 语句中必须显式声明 host 字符串
权限是按 user@host 组合精确识别的,不能省略 @'xxx' 或依赖默认值。常见错误包括:
- 执行
GRANT SELECT ON db.* TO 'api'→ 等价于'api'@'%',不是你想要的网段 - 漏掉引号:
CREATE USER 'api'@192.168.1.%直接 SQL 解析失败 - 尾部空格:
'api'@'192.168.1.% '(注意末尾空格)会导致连接时 Host 不匹配 - 没重设密码:已有用户
'api'@'192.168.1.%'但旧密码仍有效,GRANT不会覆盖密码,需加IDENTIFIED BY或单独ALTER USER
多个网段必须建多个独立用户条目
一个用户名不能绑定多个 host 模式。比如要同时允许 10.0.2.% 和 172.16.5.%,必须分别创建:
CREATE USER 'report'@'10.0.2.%' IDENTIFIED BY 'r123'; CREATE USER 'report'@'172.16.5.%' IDENTIFIED BY 'r123'; GRANT SELECT ON reports.* TO 'report'@'10.0.2.%'; GRANT SELECT ON reports.* TO 'report'@'172.16.5.%'; FLUSH PRIVILEGES;
注意两点:
- 两个用户的密码必须一致,否则从不同网段登录会因密码校验失败被拒
- 不能只建
'report'@'%'再删其他行——这等于开放全部 IP,失去段控意义
权限匹配顺序常被忽略,导致预期失效
MySQL 按 Host 字符串长度降序、再字典序升序排序,最长的优先匹配。例如:
- 存在
'app'@'192.168.1.100'和'app'@'192.168.1.%'两条记录 - 客户端从
192.168.1.100连入,实际命中的是前者(更长),不是后者 - 但如果你本意是让
192.168.1.%统一管理整个 C 段,却忘了删掉更具体的192.168.1.100条目,就会出问题 - 查当前顺序:运行
SELECT User, Host FROM mysql.user ORDER BY LENGTH(Host) DESC, Host;
真正麻烦的是:你改了权限,连不上,第一反应总去查防火墙或 bind-address,但大概率是 mysql.user 表里混着几条看似无关、实则抢跑的 host 记录。











