mysql不支持cidr掩码,仅支持%和_字符串通配符进行前缀匹配,如'192.168.1.%'可匹配该前缀的任意字符串(含非法ip),非子网计算;host字段为字面量比对,多网段需创建多个用户条目并flush privileges生效。

MySQL 不支持 CIDR 掩码(如 192.168.1.0/24),只能用 % 和 _ 通配符模拟 IP 段匹配,且必须严格按字符串前缀规则工作——不是网络层的子网计算。
host 字段的 % 是字符串通配符,不是子网通配符
MySQL 的 host 值在权限校验时被当作普通字符串比对,% 表示“零个或多个任意字符”,不理解 IP 网络概念。比如:
-
'user'@'192.168.1.%'✅ 匹配192.168.1.10、192.168.1.255、甚至192.168.1.123abc -
'user'@'192.168.1.0/24'❌ 会当作字面量主机名,无法匹配任何真实客户端 -
'user'@'192.168.%'✅ 匹配192.168.1.5、192.168.99.200,但也匹配192.168.x.y这类非法 IP(只要字符串以该前缀开头)
所以它本质是「DNS 名称或 IP 字符串的模糊前缀匹配」,不是网络层授权机制。
创建用户时 host 通配符要写在引号内,且不能加空格
错误写法会导致语法报错或权限不生效:
-
CREATE USER 'api'@'10.0.2.%' IDENTIFIED BY 'pwd';✅ 正确 -
CREATE USER 'api'@'10.0.2.% ' IDENTIFIED BY 'pwd';❌ 尾部空格会让 host 变成'10.0.2.% ',实际连接时无法匹配 -
CREATE USER 'api'@10.0.2.% IDENTIFIED BY 'pwd';❌ 缺少引号,SQL 解析失败 -
GRANT SELECT ON mydb.* TO 'api'@'10.0.2.%';✅ 授权必须与CREATE USER中的 host 完全一致(包括大小写和空格)
执行后务必运行 FLUSH PRIVILEGES;,否则变更不会加载到内存权限缓存中。
多 IP 段需创建多个用户条目,无法单条覆盖
MySQL 不允许一个用户账号绑定多个 host 模式(比如同时匹配 192.168.1.% 和 172.16.0.%)。你必须显式创建两条记录:
CREATE USER 'report'@'192.168.1.%' IDENTIFIED BY 'r123'; CREATE USER 'report'@'172.16.0.%' IDENTIFIED BY 'r123'; GRANT SELECT ON reports.* TO 'report'@'192.168.1.%'; GRANT SELECT ON reports.* TO 'report'@'172.16.0.%'; FLUSH PRIVILEGES;
注意:两个用户的密码必须相同,否则同一用户名从不同网段登录会因密码不一致被拒绝;也不能只建一个 'report'@'%' 后再删掉其他行——那等于开放全部 IP,失去段控意义。
验证是否生效:查 mysql.user 表 + 实际连接测试
光看 SHOW GRANTS 不够,因为权限合并逻辑复杂。最可靠方式是:
- 查表确认 host 存储值:
SELECT host,user FROM mysql.user WHERE user = 'report'; - 从目标 IP(如
192.168.1.50)机器上执行:mysql -u report -p -h your-mysql-host - 如果连不上,检查 MySQL 是否监听了对应网卡(
netstat -tlnp | grep :3306)、防火墙是否放行、以及客户端解析出的源 IP 是否真为预期值(NAT 或代理可能改变host)
特别容易忽略的一点:MySQL 对 localhost 和 127.0.0.1 做特殊处理——前者走 socket,后者走 TCP;而 'user'@'%' 不匹配 localhost 连接,这点常导致本地测试成功、远程失败却百思不解。











