Host '10.123.123.123' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'报错

背景:我使用nginx做了一个TCP代理,拿一个server的80端口,用来转发到另外一台服务器上的一个13306端口。偶尔在高并发连接db时,出现报错。偶尔当高并发代码被认为中断时,也出现这个报错:

Host '10.123.123.123' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts',本质原因是 MySQL 对该来源 IP 的“连接错误计数”超过了阈值 max_connect_errors,于是把这个主机暂时封锁,后续连接直接拒绝(你看到的 Connection closed by foreign host)。

问题:

Host '10.123.123.123' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'报错,本质原因是 MySQL 对该来源 IP 的“连接错误计数”超过了阈值 max_connect_errors,于是把这个主机暂时封锁,后续连接直接拒绝(你看到的 Connection closed by foreign host)。

一、为什么会触发

常见触发场景(不仅仅是“并发高”这么简单):

1.大量“半连接”或握手未完成就被关闭:Nginx 做 TCP 代理(stream)时,如果有健康检查、超时设置太短,或上层应用频繁建立后立即断开,会被 MySQL 视为连接错误。
2.网络不稳定:丢包、RST、NAT 会造成握手失败/中断。
3.端口与协议混用:你让 Nginx 在 80 端口监听再转发到 3306,如果有其他探测/扫描/HTTP 访问打到 80,该流量到了 Nginx 后被转成到 MySQL,MySQL 收到的报文不是合法握手,会累计错误。
4.连接过于“裸”:没有使用连接池,每次瞬时打开—未握手—关闭,尤其是压力测试脚本异常退出。
5.中间设备(防火墙 / 四层负载 / LVS)频繁主动断开,导致 MySQL 记为 aborted connects。
6.后端 MySQL 资源紧张(线程耗尽、backlog不够、syn flood 防护)导致握手失败,也会计数。


二、关键变量与机制

MySQL 维护一个 host cache,对每个主机计数出现的“连接错误”类别(aborted_connect / handshake failure 等)。当计数超过 max_connect_errors(默认常见值是 100),该主机被标记为 Blocked。后续连接直接拒绝。

查看:SHOW VARIABLES LIKE 'max_connect_errors';
当前统计:SHOW STATUS LIKE 'Aborted_connects';(总量)

关于'Aborted_connects'的介绍,可以参考我的另外一篇文章: https://www.cnblogs.com/pingguomang/p/19260764

 

三、立即解封

任选其一:

1)mysqladmin -uroot -p flush-hosts
2)登录(mysql -u root)后执行:FLUSH HOSTS;

四、根因修复与优化建议

1. 增大阈值(临时缓解)

SET GLOBAL max_connect_errors = 1000;
永久:在 my.cnf 中 [mysqld] 添加 max_connect_errors=1000 重启生效。
注意:只是拖延,不解决根问题。

 

2.Nginx stream 代理配置核查
示例(仅参考):

stream {
upstream mysql_backend {
server 127.0.0.1:3306 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
proxy_connect_timeout 5s;
proxy_timeout 300s;
proxy_pass mysql_backend;
# 避免额外探测模块频繁打连接(如 third-party health check)
}
}

 


检查:

1.) 是否有 HTTP/探测流量进来。若有,将 MySQL 代理端口改为非 80(如 33060),或用单独防火墙规则隔离。
2.) 关闭或调低不必要的健康检查的频率。

3.应用侧优化

  • 使用连接池(减少频繁短连接)。
  • 压测工具避免开启后立即强制 kill 连接。
  • 排查是否脚本创建连接后未执行任何 MySQL 协议握手(比如用纯 TCP 工具)。

4.网络与系统层

  • 检查防火墙 / 安全组规则是否在握手阶段断开。
  • 观察服务器的 SYN backlog 与 netstat 中的 SYN_RECV 是否异常堆积。
  • 若有 NAT(多客户端共享一个源 IP),错误汇总到同一个 IP,需减少无效尝试。

5.MySQL 服务端

  • 查看错误日志(一般是 mysqld.err)有没有 Too many aborted connects。
  • 调优:

back_log(监听队列)适当增大。
max_connections 是否过低导致拒绝再被计一次错误。
skip-name-resolve 打开可减少反向解析延迟造成的握手超时(在 my.cnf 中加入 skip-name-resolve)。


6.防止混入非 MySQL 协议流

  • 改监听端口(不要用 80)或在 Nginx 前加一层协议分流:HTTP 与 MySQL 分开。
  • 利用 Nginx stream 的 access_log 分析源连接类型,过滤异常来源。

五、排查步骤快速流程

1. FLUSH HOSTS 解封恢复业务。
2. SHOW VARIABLES / STATUS 记录 max_connect_errors 与 Aborted_connects 基线。
3. 切换代理监听端口到 33060 或 3306(避免非 MySQL 流量)。
4. 抓包(tcpdump / Wireshark)看是否大量短 RST 或半握手。
5. 应用改为持久连接池;压测脚本加 --reconnect 间隔或使用官方驱动。
6. 如果仍上涨:提高 max_connect_errors(缓解),并继续定位 handshake 失败来源 IP。

六、示例命令(仅参考)

(1) 查看变量:
mysql -uroot -p -e "SHOW VARIABLES LIKE 'max_connect_errors';"
(2) 临时调大:
mysql -uroot -p -e "SET GLOBAL max_connect_errors=1000;"
(3) 解封:
mysqladmin -uroot -p flush-hosts

七、什么时候不建议仅仅“调大”

如果 Aborted_connects 不断快速增长(比如每分钟上千),说明真实握手失败或探测打爆,不应只调大阈值;应首先隔离非协议流量 + 连接复用。

八、总结

你的问题并非 MySQL“坏了”,而是大量异常/被中断的短连接(可能来自 Nginx 端口选择、健康检查或压测方式)导致 host cache 封锁。核心策略:换端口隔离非协议流量 + 优化连接模式 + 适度提升 max_connect_errors + 定位并消除握手失败根源。

如果后续你愿意贴出 Nginx stream 配置或 MySQL 错误日志,我可以继续帮你做更精细的定向优化。需要的话告诉我。

 

posted @ 2025-11-23 15:38  苹果芒  阅读(9)  评论(0)    收藏  举报