最有效方式是MySQL不监听公网网卡+防火墙兜底+安全组前置过滤三者协同:bind-address=127.0.0.1仅限本地监听,iptables放行127.0.0.1并DROP其他3306来源,云安全组严格限制可信IP段,缺一不可。

直接禁掉外网探测最有效的方式,不是只改 bind-address,而是让 MySQL 根本不监听公网网卡 + 防火墙兜底拦截 + 安全组前置过滤。单靠一种手段容易被绕过或失效。
bind-address 设成 127.0.0.1 后为什么还能被扫到?
因为 bind-address = 127.0.0.1 只让 MySQL 监听回环接口,但扫描器扫的是你服务器的公网 IP 和 3306 端口——只要防火墙或云安全组没封,SYN 包能发过去,TCP 握手失败前就会返回 RST 或超时,扫描器照样记为“端口开放”。这不是 MySQL 暴露了,是网络层还在应答。
- 检查是否真生效:运行
netstat -tlnp | grep :3306,输出里只能有127.0.0.1:3306,不能出现*:3306或公网 IP - 常见翻车点:
skip-networking = 1和bind-address共存时,旧版 MySQL(如 5.6)会优先按skip-networking执行,导致bind-address不生效 - Docker/Pod 场景下,
127.0.0.1是容器内回环,宿主机或其他容器仍可通过桥接网段访问,必须额外配iptables或 Kubernetes NetworkPolicy
iptables 规则怎么写才不把自己锁死?
MySQL 启动时会自己连 127.0.0.1:3306 做初始化校验,如果 iptables 把所有 3306 INPUT 都 DROP,服务根本起不来。
- 必须先放行本地回环:
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 3306 -j ACCEPT - 再拒绝其他来源:
iptables -A INPUT -p tcp --dport 3306 ! -s 127.0.0.1 -j DROP(注意!前后有空格) - 别用
REJECT,用DROP:避免暴露服务存在(REJECT发 RST 包,扫描器秒识别) - 规则顺序不能错:放行规则必须在拒绝规则之前,iptables 自上而下匹配
- 保存规则:
iptables-save > /etc/iptables/rules.v4(Debian/Ubuntu)或service iptables save(CentOS 6)
云服务器必须配安全组,不能只靠 iptables
阿里云、腾讯云、AWS 的安全组是网络入口的第一道过滤,比系统内 iptables 更早生效。如果安全组已放开 3306 入向,iptables 再严也没用;但如果安全组已禁止,iptables 就收不到包——所以双层必须都配。
- 安全组策略:只放行可信 IP 段(如运维跳板机、应用服务器内网段),**不要开 0.0.0.0/0**
- 验证安全组是否生效:从外网执行
telnet 公网IP 3306,应超时或连接拒绝 - 验证 iptables 是否生效:在服务器本地执行
nc -zv 127.0.0.1 3306应通,nc -zv 公网IP 3306应失败 - 安全组配置可能被误操作清空,iptables 规则重启不失效(若已保存),二者互为备份
真正防住扫描器,关键不在“MySQL 怎么配”,而在“网络路径上哪一环先丢包”。bind-address 是 MySQL 层面的约束,iptables 是系统层面的拦截,安全组是云平台层面的隔离——三者缺一不可,且顺序不能颠倒。最容易被忽略的是安全组没关、iptables 规则没保存、或者 Docker 网络没单独处理。


















