MySQL 8.0.13+ 支持 bind-address 逗号分隔多IP(如 192.168.1.10,203.203.203.10),旧版本仅支持单值;bind-address=0.0.0.0 监听所有网卡,需配合用户权限、防火墙实现安全双IP访问。

直接说结论:bind-address = 0.0.0.0 本身不区分内网/外网,它只是让 MySQL 监听所有网卡——包括你不想暴露的外网 IP。真要“双 IP 监听”,不能只靠 bind-address,得配合用户权限、防火墙、甚至 MySQL 版本能力来分层控制。
MySQL 8.0.13+ 才支持真正意义上的多 IP 绑定
旧版本(如 5.7、8.0.12 及之前)的 bind-address 只接受单个值:127.0.0.1、192.168.1.10 或 0.0.0.0,没法写成 192.168.1.10,203.203.203.10。强行这么写会导致 mysqld 启动失败,日志里报 Unknown variable 'bind-address' 或直接退出。
从 MySQL 8.0.13 开始,bind-address 才支持逗号分隔的多个具体 IP:
bind-address = 192.168.1.10,203.203.203.10
注意两点:
- 每个 IP 必须是明确地址,不能含通配符(
0.0.0.0、*、::都不允许) - IPv4 和 IPv6 混用也合法,比如
192.168.1.10,::1 - 如果服务器有多个网卡但只列了其中两个,其余网卡上的 IP 就完全不会监听
bind-address = 0.0.0.0 是最常见误用点
很多人以为设成 0.0.0.0 就能“灵活控制”,实际它等于把所有网卡全打开,连 Docker 容器桥接口、Kubernetes CNI 接口都可能被监听——只要网络层可达,就可能被连上。
典型风险场景:
- 服务器同时有内网
192.168.1.10和外网203.203.203.10,bind-address = 0.0.0.0后,外网 IP 的 3306 端口也会出现在netstat -tuln | grep :3306输出里 - 没配防火墙或用户权限时,任意公网 IP 都能尝试连接,暴力破解成功率直线上升
- 云厂商安全组若只封了外网端口,但宿主机防火墙没关,仍可能被绕过
真正可控的“双 IP”策略:绑定 + 权限 + 防火墙三层隔离
不依赖高版本 MySQL,也能安全实现“内网可连、外网受限”。关键不是让 MySQL 自己选监听谁,而是让它只听内网 IP,再靠其他机制放行特定外网请求。
推荐组合操作:
-
MySQL 配置:设
bind-address = 192.168.1.10(仅内网 IP),确保skip-networking = 0(保持 TCP 开启) -
用户授权:创建两个用户
— 内网用户:GRANT ALL ON *.* TO 'app'@'192.168.1.%';
— 外网用户(严格限制):GRANT SELECT ON mydb.* TO 'report'@'203.203.203.50';(只给某台跳板机) -
防火墙规则(以 firewalld 为例):
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.203.203.50" port port="3306" protocol="tcp" accept'firewall-cmd --permanent --remove-service=mysql(关掉默认 mysql service 规则)firewall-cmd --reload
验证是否生效,别只看 netstat
netstat -tuln | grep :3306 只能看出监听地址,看不出权限和防火墙是否拦住。必须三步验证:
- 执行
mysql -h 192.168.1.10 -u app -p—— 应该成功 - 执行
mysql -h 203.203.203.10 -u app -p—— 应该报Can't connect to MySQL server(连接被拒,说明 bind 或防火墙起效) - 执行
mysql -h 203.203.203.50 -u report -p—— 应该成功(前提是已授权且防火墙放行) - 再进 MySQL 执行
SHOW VARIABLES LIKE 'bind_address';,确认输出是192.168.1.10而非0.0.0.0
最容易被忽略的是:改完 my.cnf 后忘了 systemctl restart mysqld,或者重启了但没检查错误日志(/var/log/mysqld.log 或 journalctl -u mysqld -n 50),导致配置根本没加载。











