ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

数据库连接失败 max_connect_errors

数据库连接失败 max_connect_errors max_connect_errors 导致 IP 被封一次 Docker 部署 MySQL 连不上的排错实录元描述本地能连、服务器却一直 Connection refused本文复盘一次由 Docker 重启轰炸触发max_connect_errors、导致应用服务器 IP 被 MariaDB 封锁的真实排错用 telnet 秒级判定、FLUSH HOSTS 即时解封并揭示 env_file 未注入这一隐藏陷阱最后给出调大阈值与连接池容错的永久根治方案。建议收藏。一句话结论先看这里如果你本地能连数据库、同样的代码上服务器却报Connection refused / Communications link failure先别怀疑密码——大概率是应用服务器 IP 被 MySQL/MariaDB 的max_connect_errors安全机制拉黑了。用telnet 数据库IP 3306看到Host ... is blocked because of many connection errors即可确诊在数据库侧执行一条FLUSH HOSTS;就能解封。本文记录我从踩坑到根治的完整过程。一、背景我的部署环境先交代环境方便你对照后端Spring Boot 3.3 Hibernate JPA HikariCP通过 Docker 部署。数据库远程MariaDB 10.11.14编排docker-compose.yml配了env_file: - .env和restart: unless-stopped。一切都正常跑过本地直到我把它搬上服务器。二、现象本地能连服务器_connection refused本地mvn spring-boot:run一切正常。上服务器用 Docker 跑容器一启动就在连库阶段炸com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure Caused by: java.net.ConnectException: Connection refused (Connection refused)每次docker compose restart都一样应用根本起不来。排错第一原则先看错误是哪一层。Connection refused是TCP 层被拒不是账号密码错那会报Access denied。所以它要么是地址/端口写错要么是对方不让你连——后者正是 IP 被封。三、排查telnet 一眼看出被拉黑怀疑是网络层问题我在应用服务器上直接探数据库端口telnetip3306立刻返回不是超时Trying ip... Connected to ip. Escape character is ^]. Host 我的ip is blocked because of many connection errors; unblock with mysqladmin flush-hosts这行Host ... is blocked because of many connection errors就是铁证——我的应用服务器 IP 被 MariaDB 拉黑了。关键区分telnet秒回拒绝信息 被拉黑如果一直超时 防火墙/地址端口不通。两者解法完全不同别混淆。四、根因max_connect_errors 是什么为何被触发4.1 什么是 max_connect_errorsmax_connect_errors是 MySQL/MariaDB 的服务端安全参数默认值 100来源MySQL 8.0 官方手册server-system-variables访问于 2026-08-21。它的逻辑是如果某个客户端 IP 连续出现太多次连接中途失败没完成握手就被中断数据库就认为它可能是扫描器/攻击者于是对该 IP 维度永久封锁——此后该 IP 的所有连接请求都在 TCP 层被直接拒绝。它统计的是失败连接次数不是总连接数封锁按IP维度与账号、库无关。4.2 我的 IP 为什么会被封真相不是代码写错而是部署早期的不稳定期后端首次上服务器时.env一度缺失 / 环境变量没注入容器连的是默认localhost:3306连不上 → 抛异常退出 → 因为restart: unless-stopped容器被自动拉起再连 → 再失败 → 再拉起……短短几分钟里应用服务器 IP 对 MariaDB 发起了几十上百次失败连接瞬间超过max_connect_errors 100IP 被拉黑。于是出现最诡异的现象哪怕我后来把配置改对了连接依然Connection refused——因为数据库根本不让我进握手阶段。这也解释了本地能连、服务器不能连本地开发机 IP 从没触发过失败计数不在黑名单里。五、解决一条 FLUSH HOSTS 解封解封只需在数据库服务器上执行一条命令清空主机缓存、解除所有被拉黑的 IP-- 登录数据库后执行FLUSH HOSTS;命令行版不用进交互界面mysqladmin flush-hosts-uroot-p# 或本机有权限时mysql-uroot-p-eFLUSH HOSTS;执行后再回到应用服务器telnet ip 3306应当能看到正常的5.5.5-10.11.14-MariaDB握手横幅后端也能连上了。FLUSH HOSTS即时全局生效、不需要重启数据库。但它只是临时解封——根因配置错导致疯狂重连不解决几分钟内又会触发。六、最容易漏掉的第二层env_file 根本没注入我FLUSH HOSTS之后重启结果还是 Connection refused。这才发现第二个坑。机制重点docker-compose.yml里的env_file: - .env只在容器被创建那一次把变量固化进环境。docker compose restart/docker start只是重启已有容器不会重新读取.env。而我最初的旧容器是手动docker run起来的里面压根没有MYSQL_*变量一直用application.yml的默认localhost:3306——解封了也还是在连错误地址。验证dockerinspect fraud-shield-backend--format{{range .Config.Env}}{{println .}}{{end}}|grepMYSQL# 毫无输出 → 实锤没注入cat.env|grepMYSQL_HOST解决删容器重建让 compose 重新读.envdockerrm-ffraud-shield-backenddockercompose up-ddockerinspect fraud-shield-backend|grepMYSQL口诀改了.env或怀疑环境变量不对永远docker rm -fdocker compose up -d重建别指望 restart 生效。七、根治别让它在生产环境再发生7.1 调大阈值治标但实用在数据库配置文件如/etc/mysql/my.cnf或 MariaDB 的50-server.cnf加[mysqld] max_connect_errors 100000重启数据库生效在线临时改SET GLOBAL max_connect_errors 100000;但重启会失效建议写进配置文件。把它调大不是纵容攻击而是避免正常部署抖动被误杀真正的防爆破应靠防火墙/安全组限制来源 IP。7.2 应用侧连接池容错HikariCP 配置里加初始探测避免一启动就海量建连spring:datasource:hikari:initial-size:1connection-init-sql:SELECT 1max-lifetime:18000007.3 消除重连来源部署确认能连上之前先把restart临时改成no手动起一次验证再改回unless-stopped避免配置错 → 无限重启 → 打爆失败计数的死循环。八、标准排查清单可直接抄# ① 应用服务器上确认是否被拉黑telnetip3306# 看到 Host ... is blocked → 被封走 ②# ② 数据库服务器解封mysql-uroot-p-eFLUSH HOSTS;# ③ 回应用服务器确认解封应进入握手横幅telnetip3306# ④ 仍 Connection refused查容器是否注入了正确配置dockerinspect fraud-shield-backend|grepMYSQL# 无输出 → 没注入走 ⑤# ⑤ 删旧容器、compose 重建重读 .envdockerrm-ffraud-shield-backenddockercompose up-ddockerinspect fraud-shield-backend|grepMYSQL_HOST# ⑥ 看日志确认启动成功dockerlogs-ffraud-shield-backend# 期望Started ... in xx seconds且无 Communications link failure九、FAQQConnection refused 和 Access denied 有什么区别A前者是 TCP 层被拒IP 被封 / 地址端口错 / 服务没监听连握手都进不去后者是连上了但账号密码或权限不对。先看清是哪一层再动手。QFLUSH HOSTS 之后还会再被封吗A会如果配置错误导致的重连轰炸不解决。它是临时解封根治见第七节的调阈值 连接池 消除重连来源。Q本地能连为什么服务器不能连A封锁按 IP 维度。你本地开发机 IP 不在黑名单应用服务器 IP 可能因为部署抖动被封了。永远在应用服务器这一侧去 telnet/连库。Q把 max_connect_errors 设成 0 是不是就永不被封A不是某些版本里 0 含义相反表示不限制且这治标不治本。正确做法是修正配置 配合防火墙限制来源 IP。Qdocker compose restart 会重新加载 .env 吗A不会。env_file只在容器创建时注入restart 不重读。改了.env必须删容器重建。十、结语max_connect_errors引发的连接失败本质是**“配置错 → 容器疯狂重启 → 失败连接爆表 → 数据库按 IP 拉黑”** 的连锁反应跟业务代码、账号密码无关。记住三条就够用判定靠 telnet秒回Host ... is blocked就是被封解封靠 FLUSH HOSTS数据库侧执行即时全局生效别漏第二层解封后还连不上多半是容器.env没注入删容器重建。把它和环境变量注入连接池配置一起当成部署 checklist下次上服务器能省掉大量试错时间。参考资料MySQL 8.0 官方手册 —max_connect_errors系统变量https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_connect_errors 访问于 2026-08-21MariaDB 知识库 — Server System Variablesmax_connect_errorshttps://mariadb.com/kb/en/server-system-variables/#max_connect_errors 访问于 2026-08-21
返回列表