应先放行本地回环(-A INPUT -s 127.0.0.1 -p tcp --dport 3306 -j ACCEPT),再拒绝外部访问(-A INPUT -p tcp --dport 3306 ! -s 127.0.0.1 -j DROP),并配合安全组与 bind-address 协同防护。

iptables 怎么封掉 MySQL 默认端口(3306)
直接封 3306 是最常见也最容易出问题的操作——封错方向或漏掉本地回环,会导致 MySQL 自己连不上自己。mysqld 启动时会尝试连接本地 127.0.0.1:3306 做初始化检查,如果 iptables 把 INPUT 链里所有 3306 都 DROP,服务根本起不来。
实操建议:
- 优先用
-A INPUT -s 127.0.0.1 -p tcp --dport 3306 -j ACCEPT放行本地回环,再加拒绝规则 - 封外部访问时,用
-A INPUT -p tcp --dport 3306 ! -s 127.0.0.1 -j DROP(注意!前后有空格) - 别用
REJECT,改用DROP:避免暴露服务器运行了 MySQL(REJECT会发 RST 包,扫端口时一眼识别) - 规则顺序很重要:iptables 自上而下匹配,放行规则必须写在拒绝规则之前
云服务器安全组 vs iptables:哪个该优先配
云厂商(阿里云、腾讯云、AWS)的安全组是网络层的第一道过滤,比系统内 iptables 更早生效。如果安全组已经禁止了 3306 入向,iptables 再怎么配都收不到包——但反过来,如果安全组开了 3306,iptables 就必须兜底。
实操建议:
- 生产环境必须双层控制:安全组只放行可信 IP 段(如运维跳板机、应用服务器内网段),iptables 做二次校验
- 别依赖单一防护:安全组配置可能被误操作清空,iptables 规则重启不失效(若已保存)
- 查安全组是否生效,用
telnet 公网IP 3306从外网测;查 iptables 是否生效,用curl -v telnet://127.0.0.1:3306或本地 nc 测
MySQL 绑定地址(bind-address)和防火墙的关系
bind-address 配置决定 MySQL 监听哪些网卡,它和防火墙不是互斥关系,而是协同失效点。比如设成 127.0.0.1 后,MySQL 根本不监听公网网卡,iptables 就算没规则,外网也连不上——但很多人误以为“这样就安全了”,其实只要改一行配置就能暴露。
实操建议:
- 确认当前绑定:查
my.cnf里的bind-address,运行中可执行SELECT @@bind_address; - 设为
127.0.0.1是最省事的限制方式,但前提是应用和 MySQL 在同一台机器;跨机器必须放开,此时防火墙就成关键防线 - 别设成
0.0.0.0然后只靠防火墙拦——等于把门敞开再挂把锁,攻击者一旦绕过防火墙(比如规则被删、策略错误),立刻裸奔
MySQL 连接被拒但没报错?可能是防火墙静默丢包
典型现象:客户端 connect 超时(不是 Connection refused),tcpdump 看不到 SYN-ACK 返回,iptables -L -n -v 显示对应规则 hit 计数在涨——基本就是 DROP 导致的静默丢包。
实操建议:
- 排查时先关 iptables(
systemctl stop iptables或iptables -F),确认是否恢复;再逐步加回规则定位哪条导致 - 记录日志辅助判断:临时把 DROP 改成
-j LOG --log-prefix "iptables-drop-mysql: ",然后tail -f /var/log/messages看是否真有匹配 - 云服务器还要检查:安全组是否关联了正确实例、是否选错网络类型(经典网络/VPC)、ECS 实例是否绑定了多个安全组且其中某个放行了 3306
真正麻烦的是规则链嵌套和默认策略——比如 INPUT 默认是 ACCEPT,你加了一条 DROP 却忘了最后补个 ACCEPT,结果所有非 3306 流量也被拦了。这种问题不会立刻报错,但会让 SSH、HTTP 全部失联。


















