MySQL无法通过GRANT或DROP USER封禁IP段,必须用iptables -I在链首插入DROP规则阻断TCP握手,如iptables -I INPUT -s 192.168.5.0/24 -p tcp --dport 3306 -j DROP,并配合iprange模块或白名单策略。

MySQL 本身不提供“封禁某 IP 段”的全局开关,靠 GRANT 或 DROP USER 只能控制已建立连接后的权限,拦不住 TCP 握手;真要阻断连接请求,必须在系统网络层用 iptables 或 firewalld 动手。
iptables 封禁 IP 段必须用 -I 插入最前规则
很多人写 iptables -A INPUT ... -j DROP,结果规则排在 ACCEPT 后面,被放行了。MySQL 默认监听 3306 端口,只要该端口对某 IP 开放,mysqld 就会响应 SYN 包——哪怕后续鉴权失败,也会暴露服务存在。
- 正确做法是用
-I(insert)把 DROP 规则插到链首:iptables -I INPUT -s 192.168.5.0/24 -p tcp --dport 3306 -j DROP - 注意:Linux 内核不原生支持 CIDR 在
-s中直接写/24,需启用xt_iprange模块或改用--src-range;更稳妥的是用两次规则覆盖 C 段:iptables -I INPUT -s 192.168.5.1 -s 192.168.5.254 -p tcp --dport 3306 -j DROP(实际应配合iprange模块) - 封禁后必须测试是否“无响应”:
telnet 192.168.5.10 3306应超时或直接拒绝,而非返回Connection refused(后者说明 MySQL 已响应,防火墙没生效)
mysql.user 表里不能直接写 CIDR,% 不等于子网掩码
MySQL 的 Host 字段只认 SQL 模式通配符:% 匹配任意长度字符串,_ 匹配单字符,不解析 CIDR、不校验 IP 合法性。写 'user'@'192.168.5.%' 看似限制 C 段,实则也会匹配 192.168.5.abc.example.com 或 192.168.5.1234(MySQL 静默截断非法部分)。
- 想真正限定 192.168.5.0/24,只能建多个具体账号(不现实)或放弃纯 MySQL 方案
- 生产环境若必须用
%,务必搭配防火墙白名单:只放行可信网段的 3306 入向流量,iptables或云安全组优先级高于 MySQL 权限 -
UPDATE mysql.user SET Host='192.168.5.%' WHERE User='u'是危险操作——它会覆盖原有 host,且 MySQL 8.0+ 不允许直接 UPDATEmysql.user,应改用DROP USER+CREATE USER
bind-address 和 skip_name_resolve 影响 host 匹配行为
bind-address 控制 MySQL 监听哪个网卡,不是 IP 限制手段;但若设为 127.0.0.1,外部 IP 根本连不上——这是最彻底的“禁止”,但代价是牺牲所有远程访问。
-
skip_name_resolve=ON强制 MySQL 只用客户端 IP 地址匹配Host字段,禁用 DNS 反查;否则当客户端 IP 被反解成域名(如host123.example.com),而你只建了'user'@'192.168.5.10',就会匹配失败 - 检查当前配置:
SELECT @@bind_address, @@skip_name_resolve; - 修改需重启:
bind-address = 0.0.0.0(监听所有)或192.168.1.10(仅内网网卡),配合防火墙才安全
最易被忽略的一点:MySQL 用户权限按 User@Host 组合存储,'root'@'192.168.5.10' 和 'root'@'%' 是两条完全独立的记录,删错一条,另一条仍可连。封禁前先查 SELECT User, Host FROM mysql.user WHERE User = 'root';,别凭印象操作。


















