在 CentOS 8 上使用 firewall-cmd 永久开放 3306 端口,核心命令是添加端口规则并重载配置。但需高度注意:CentOS 8 已停止维护,且数据库端口直接暴露在公网存在极高安全风险。
先说结论:操作命令简单,但涉及生产安全需谨慎评估网络暴露面。
- 适合:内网可信环境或已配置安全组限制的云服务器
- 先准备:确认 MySQL 服务监听地址及当前防火墙状态
- 验收:通过远程连接测试及防火墙规则列表确认生效
命令速用版
sudo firewall-cmd `--permanent` `--add-port`=3306/tcp
sudo firewall-cmd `--reload`
原理简述
CentOS 8 默认使用 firewalld 作为动态防火墙管理器。规则分为“运行时”和“永久”两种。仅添加永久规则而不重载,当前会话不会生效;重载后永久规则才会写入运行时配置。
分步处理
1. 检查防火墙服务状态,确保 firewalld 正在运行:
sudo systemctl status firewalld
若未运行,启动服务:
sudo systemctl start firewalld
sudo systemctl enable firewalld
2. 添加 3306 端口到 public 区域(默认区域),并标记为永久:
sudo firewall-cmd `--permanent` `--add-port`=3306/tcp
3. 重载防火墙配置,使永久规则立即生效:
sudo firewall-cmd `--reload`
4. (强烈建议)限制访问来源 IP,避免全开放风险:
sudo firewall-cmd `--permanent` `--remove-port`=3306/tcp
sudo firewall-cmd `--permanent` `--add-rich-rule`='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'
再次重载生效:
sudo firewall-cmd `--reload`
验证方法
1. 查看当前区域已开放的端口列表:
sudo firewall-cmd `--list-ports`
2. 检查本地监听状态,确认 MySQL 正在监听 3306:
sudo ss -tlnp | grep 3306
3. 从另一台机器尝试连接,或使用 telnet/nc 测试端口连通性:
telnet <服务器 IP> 3306
nc -zv <服务器 IP> 3306
故障排查:连接被拒绝 (Connection Refused)
若防火墙已开放但仍无法连接,请按以下顺序排查:
1. 检查 MySQL 是否监听外网 IP:
sudo ss -tlnp | grep 3306
若显示 127.0.0.1:3306,说明 MySQL 仅监听本地。需修改 /etc/my.cnf,设置 bind-address = 0.0.0.0 或注释该行,然后重启 MySQL。
2. 检查 SELinux 状态:
SELinux 可能阻止 MySQL 绑定非标准端口或网络访问。临时设置为 Permissive 模式测试:
sudo setenforce 0
若测试成功,建议配置 SELinux 策略而非长期关闭:
sudo setsebool -P mysql_connect_any 1
3. 检查云平台安全组:
云服务器(如阿里云、AWS)需在控制台安全组规则中放行 TCP 3306 端口,系统防火墙放行仅是内部条件。
常见坑与系统建议
1. 忘记重载:添加 `--permanent` 后必须执行 `--reload`,否则重启前不生效。
2. 全开放风险:直接开放 3306 到 0.0.0.0/0 极易导致数据库被爆破勒索,务必配合安全组或 rich-rule 限制源 IP。
3. 系统生命周期风险:CentOS 8 已于 2021 年 12 月 31 日停止维护,不再接收安全更新。作为生产环境,建议规划迁移至替代系统。
4. 迁移指南:
- Rocky Linux / AlmaLinux:1:1 兼容 RHEL/CentOS 生态,迁移成本最低。
- 操作:使用
migrate2rocky或almalinux-deploy脚本可在原地升级,但生产环境建议备份后重装。
参考来源
- Red Hat Enterprise Linux 8 Security Guide - Using Firewalls
- CentOS Project - CentOS Linux End of Life
- MySQL Documentation - Connecting to the MySQL Server