MySQL容器严禁-p 3306:3306映射至公网,应使用Docker自定义网络(如mysql-net)隔离通信,宿主机防火墙禁止所有3306入向流量,bind-address设为0.0.0.0并配合网段精确授权用户(如'app'@'172.18.0.%'),同时调高nf_conntrack超时值防中断。

MySQL容器不暴露3306端口到宿主机公网
直接 -p 3306:3306 映射并开放防火墙,等于把登录界面贴在互联网上供扫描器挨个试密码。轻量网关(如 Nginx、Traefik 或云厂商的 API 网关)本身不转发数据库流量,所以 MySQL 必须彻底与公网隔离。
正确做法是:容器启动时完全不映射 3306 到宿主机外网接口,改用 Docker 自定义网络通信:
- 创建专用桥接网络:
docker network create mysql-net - 启动 MySQL 容器时指定该网络:
docker run --network=mysql-net -e MYSQL_ROOT_PASSWORD=xxx -d mysql:8.0 - 应用服务容器也加入同一网络:
--network=mysql-net,它们之间通过容器名(如mysql)直连 - 宿主机防火墙禁止所有入向 3306 流量:
sudo ufw deny 3306(Ubuntu)或firewall-cmd --remove-port=3306/tcp --permanent(CentOS)
bind-address 与 Docker 网络必须对齐
常见错误是容器内 my.cnf 写了 bind-address = 127.0.0.1,但又想让同网络的其他容器访问——结果就是 telnet mysql-container 3306 成功,mysql -h mysql -P 3306 -u root -p 却报 Access denied 或超时。
关键判断依据是容器内实际监听地址:
- 进容器检查:
docker exec -it mysql-container ss -tln | grep :3306 - 期望输出含
*:3306(表示监听所有接口)或172.18.0.2:3306(具体网段 IP),而非仅127.0.0.1:3306 - 若用自定义网络,
bind-address应设为0.0.0.0或留空(默认行为);若只允许本地应用,可设为宿主机内网 IP(如192.168.5.10),但需确保应用走该地址且防火墙白名单放行
用户权限必须按网段精确授权
MySQL 的 @'%' 是高危配置,哪怕容器只在内网运行,也要避免通配符主机。权限必须和 Docker 网络子网严格匹配。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
例如容器网络是 172.18.0.0/16,就应创建用户:
CREATE USER 'app'@'172.18.0.%' IDENTIFIED BY 'StrongPass!2024'; GRANT SELECT, INSERT ON mydb.* TO 'app'@'172.18.0.%'; FLUSH PRIVILEGES;
同时撤销不安全账号:
DROP USER IF EXISTS 'root'@'%';-
DELETE FROM mysql.user WHERE host = '%'; FLUSH PRIVILEGES;(谨慎执行) - 确认生效:
SELECT user, host FROM mysql.user;
conntrack 超时导致连接中断不能忽略
长事务或空闲连接突然断开,MySQL 错误日志却无记录?大概率是宿主机 conntrack 表提前清理了连接状态。Docker 宿主机内核参数 net.netfilter.nf_conntrack_tcp_timeout_established 在某些云环境被压到 300 秒以下,而 MySQL 默认 wait_timeout = 28800(8 小时)。
修复方式:
- 查当前值:
sysctl net.netfilter.nf_conntrack_tcp_timeout_established - 临时调高:
sudo sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600 - 永久生效:写入
/etc/sysctl.conf并sudo sysctl -p - 应用层配合:客户端启用
autoReconnect=true(JDBC)或设置合理的连接池 idle timeout(如小于 300 秒)
这个点容易被当成 MySQL 配置问题排查半天,其实根源在宿主机网络栈。轻量网关后方的 MySQL 往往部署在资源受限的实例上,内核参数更易被云厂商定制覆盖,必须主动验证。

















