back_log管的是三次握手完成、内核已放入全连接队列但mysql尚未accept()捞取的等待连接段;它不处理syn(由tcp_max_syn_backlog管)、也不管建连后行为(由max_connections和wait_timeout管),溢出时客户端直接报connection refused或超时。

back_log 不是用来“应对高并发连接”的,它只负责接住那一小段“刚握手完、还没被 MySQL 拿去认证”的连接请求;真连不上,大概率不是它的问题,而是你没看清连接卡在哪一层。
back_log 实际管的是哪一段连接?
它不处理客户端发来的第一个 SYN(那是 tcp_max_syn_backlog 管的),也不管连接建好后干啥(那是 max_connections 和 wait_timeout 的事)。它只管:三次握手已完成、内核已把连接放进全连接队列(ACCEPT queue)、但 MySQL 还没调 accept() 把它捞进自己线程池的那一小段“等待区”。
常见错误现象:unauthenticated user 状态大量堆积,SHOW STATUS LIKE 'Aborted_connects' 持续上涨,但 Threads_connected 远低于 max_connections。
- 这个队列满的直接表现是客户端报
Connection refused或超时,错误日志里却找不到对应记录 - 它不消耗 MySQL 线程,但一旦被
accept()进来,立刻占一个线程——如果密码错或账号不存在,该线程还会短暂存活,加剧拥塞 - MySQL 5.6.6+ 默认值是
50 + (max_connections / 5),上限 900;老版本固定 50,基本不够用
为什么改了 back_log 客户端还是连不上?
因为 back_log 的实际生效值,永远取你配置值和系统参数 net.core.somaxconn 的较小者。设成 1024 没用,如果 net.core.somaxconn = 128,MySQL 启动时会静默截断并写 warning 到 error log。
- 查当前限制:
sysctl net.core.somaxconn和SHOW VARIABLES LIKE 'back_log' - 临时调大系统值:
sudo sysctl -w net.core.somaxconn=2048,再写入/etc/sysctl.conf持久化 - MySQL 配置中设
back_log = 1024(建议 ≤net.core.somaxconn值),然后重启mysqld(运行时SET不生效) - 验证是否生效:
ss -lnt | grep :3306,看Recv-Q能否撑到接近你设的值
back_log 和 max_connections 完全不是一回事
混淆这两者是最常见的误操作。前者是 TCP 层“排队通道”,后者是 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 > 60
别忽略内核队列溢出这个底层信号
即使 back_log 和 net.core.somaxconn 都调大了,如果 netstat -s | grep -i "listen overflows" 输出非零,说明内核队列已经溢出——MySQL 根本收不到那些连接请求,所有调优都白搭。
Linux 推荐 net.core.somaxconn ≤ 512,云主机上设太高(比如 2048+)反而可能触发内核丢包,表现为偶发性连接失败,而非稳定超时。更危险的是,tcp_abort_on_overflow 若为 1,溢出时会直接 RST,客户端感知就是“拒绝连接”。











