调大back_log仅缓解tcp连接请求队列溢出,不能解决max_connections耗尽或连接泄漏;真正连不上常因net.core.somaxconn限制或mysql处理accept()过慢,需同步调系统参数并排查sleep连接泄漏。

调大 back_log 本身不能解决连接溢出,它只缓解“连不上”的假性溢出;真溢出必须查 max_connections 和连接泄漏。
为什么改 back_log 后客户端还是连不上
常见现象是:应用日志里没报 Too many connections,而是直接超时、Connection refused 或握手失败。这说明连接请求压根没进 MySQL,被 Linux 内核 TCP 队列丢弃了——back_log 控制的就是这个队列长度(SYN queue),不是 MySQL 自己的连接池。
它默认只有 50~80,高并发建连(比如健康检查每秒打 100 次、微服务启动潮)瞬间就满。但光改 back_log 没用,因为:
-
back_log受系统级net.core.somaxconn限制,设成 1024 但somaxconn=128,MySQL 启动时会自动截断并写 warning 到 error log - 即使队列变长,若 MySQL 处理
accept()的速度跟不上(比如慢查询堵住线程、CPU 过载),新连接仍会被丢 - 真正耗尽的是
max_connections,不是队列;队列满只是“前端拦不住”,连接数满才是“后端装不下”
如何安全调大 back_log
必须同步调系统参数,否则无效。操作顺序不能错:
- 先查当前值:
sysctl net.core.somaxconn和SHOW VARIABLES LIKE 'back_log'; - 临时调大系统上限:
sudo sysctl -w net.core.somaxconn=2048,并写入/etc/sysctl.conf持久化 - 再改 MySQL 配置,在
[mysqld]段加:back_log = 1024(建议 ≤somaxconn值) - 重启 MySQL(注意:MySQL 8.0+ 中该值在启动时校验,不满足会静默降级)
- 验证是否生效:
ss -lnt | grep :3306看 Recv-Q 是否能撑到接近你设的值
back_log 和 max_connections 的关系到底是什么
两者完全独立,但常被混为一谈:
-
back_log是 TCP 层的“等待区”,存的是刚发来 SYN、还没完成三次握手的连接请求 -
max_connections是 MySQL 层的“工作区”,存的是已完成握手、已认证、正在执行或休眠的连接 - 如果
back_log溢出,客户端连不上,错误不在 MySQL 日志里;如果max_connections溢出,客户端能握手成功,但立刻收到Too many connections - 一个健康配置:假设你设
max_connections = 1000,那back_log设 256~512 足够;设到 2000 就过度了,反而可能因内核队列过长掩盖真实连接泄漏问题
真正该优先排查的,其实是连接没释放
很多所谓“高并发压爆连接数”的问题,根源是连接泄漏,不是并发真高:
- 查长期 Sleep 的连接:
SELECT ID, USER, HOST, TIME FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300; - PHP 持久连接、Python
mysql-connector异常路径漏close()、Java 应用未配置连接池回收策略,都会让连接钉死在Sleep状态 -
wait_timeout默认 8 小时,对 Web 应用太长,建议调到 300~900 秒,配合连接池的maxLifetime使用 - 别迷信
back_log调优——它只是缓冲层,不是扩容手段;连接池配得比max_connections还大、应用不关连接,再大的队列也救不了
最易被忽略的一点:back_log 调得再大,也挡不住持续泄漏的连接;而一次没 KILL 干净的僵死连接,可能比十倍流量更早压垮数据库。











