iptables必须先放行127.0.0.1:3306,否则mysqld启动时因自检连接被阻塞而卡住,表现为systemctl start mysql超时、日志仅显示模糊的“can’t connect to local mysql server”错误;正确做法是在所有拒绝规则前插入iptables -a input -s 127.0.0.1 -p tcp --dport 3306 -j accept,且drop规则须置于白名单之后,ufw还需显式允许lo接口。

iptables 必须先放行 127.0.0.1 才能启动 mysqld
MySQL 启动时会主动连接 127.0.0.1:3306 做初始化自检,如果 INPUT 链里没有明确放行这条流量,服务直接卡住,日志里只显示类似 Can’t connect to local MySQL server 的模糊错误。
常见错误现象:
- 执行
systemctl start mysql后无响应、超时失败 -
journalctl -u mysql看不到明显报错,或只提示 socket 连接失败 - 手动运行
mysqld --console会卡在 “Starting MySQL daemon” 步骤
正确做法是:在任何拒绝规则之前,必须插入这条:
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
注意:! -s 写成 !-s 或 !- s 会导致规则语法无效;-s 127.0.0.1 不能省略协议和端口限定,否则可能被后续规则覆盖。
白名单规则要写在 DROP 之前,且用 DROP 不要用 REJECT
iptables 规则按顺序从上到下匹配,一旦命中就停止。把 DROP 放在白名单前面,等于直接封死所有 3306 流量。
典型错误顺序(危险):
iptables -A INPUT -p tcp --dport 3306 -j DROP iptables -A INPUT -s 192.168.1.50 -p tcp --dport 3306 -j ACCEPT
正确顺序(放行优先):
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 3306 -j ACCEPT iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 3306 -j ACCEPT iptables -A INPUT -p tcp --dport 3306 ! -s 127.0.0.1 -j DROP
用 DROP 而非 REJECT 的原因:
-
REJECT会发 RST 包,暴露“这里跑着 MySQL”,方便端口扫描识别 -
DROP是静默丢包,外部探测表现为超时,隐蔽性更强
ufw 配置必须显式放行 lo 接口,否则本地回环照样被拦
ufw 默认策略是「入向全部拒绝」,但它不自动豁免 lo(本地回环)接口——而 MySQL 自检依赖的就是 lo 上的 127.0.0.1 流量。
如果你只运行了:
ufw allow from 192.168.1.50 to any port 3306
那么 mysqld 依然起不来。必须补上:
ufw allow in on lo
之后再加白名单,并确认启用:
-
ufw status verbose输出中应同时出现Anywhere on lo和你配置的192.168.1.50条目 - 没执行
ufw enable,所有规则都不生效 - 别漏掉
proto tcp,否则 UDP 流量可能意外匹配(虽然 MySQL 不用 UDP,但严谨起见)
云服务器必须同步配安全组,iptables 只是第二道防线
阿里云、腾讯云、AWS 的安全组是网络层第一道过滤,包根本进不了操作系统。也就是说:
- 安全组没开 3306 →
telnet your-public-ip 3306必然超时,iptables 再细也没用 - 安全组开了 3306 → iptables / ufw 才真正开始工作,这时才轮到白名单和 DROP 规则起效
生产环境推荐双控:
- 安全组:只放行跳板机 IP、应用服务器内网段(如
10.0.1.0/24) - iptables / ufw:再做一层校验,比如只允许其中某个具体 IP(
10.0.1.23)连 3306
容易被忽略的一点:安全组规则删了不会告警,而 iptables 若已保存(如写入 /etc/iptables/rules.v4),重启后自动加载——这个差异会让故障排查变难。











