back_log控制MySQL监听队列中已完成三次握手但未被accept()处理的连接请求数量,防止瞬时高并发连接洪峰导致内核丢弃请求;其值不能超过系统tcp_max_syn_backlog限制,否则无效。

back_log 不是防“慢速连接攻击”的参数,它防的是“瞬间高并发连接请求压垮监听队列”——两者机制完全不同,用错方向会完全失效。
back_log 实际作用是什么
back_log 控制 MySQL TCP 监听队列中「已完成三次握手但尚未被 accept() 处理」的连接请求数量。它不处理数据传输慢、连接后长期空闲或发送极慢请求的场景(那是 slowloris 类攻击),只管「新连接建立洪峰」是否被内核丢弃。
常见错误现象:unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 大量堆积,同时 show status like 'Aborted_connects'; 持续上涨,但 Threads_connected 却没到 max_connections 上限。
- Linux 内核限制了这个队列上限:
/proc/sys/net/ipv4/tcp_max_syn_backlog(默认 1024),back_log 设再大也无效 - MySQL 5.6.6+ 默认值为
50 + (max_connections / 5),上限 900;老版本固定 50,明显不够 - 真实瓶颈常在 OS 层:若
netstat -s | grep -i "listen overflows"有非零输出,说明内核队列已溢出,MySQL 根本收不到连接请求
怎么安全调大 back_log
不能盲目设成 1024 或更高,必须和系统内核参数协同调整,否则只是配置幻觉。
- 先查当前内核上限:
cat /proc/sys/net/ipv4/tcp_max_syn_backlog,生产环境建议保持 ≤ 512(避免 SYN 队列过长引发重传或丢包) - 再查 MySQL 当前值:
show variables like 'back_log';,若低于内核值,可同步上调,例如设为 500 - 修改
my.cnf的[mysqld]段:back_log = 500,然后重启 mysqld(运行时 SET 不生效) - 顺带检查并调大 OS 参数(需 root):
echo 512 > /proc/sys/net/ipv4/tcp_max_syn_backlog,并写入/etc/sysctl.conf持久化
为什么光调 back_log 防不住拒绝服务
back_log 只缓解连接建立阶段的积压,对已建立连接后的资源耗尽(如大量空闲连接占满线程、慢查询吃光 CPU)毫无作用。
- 攻击者用短连接快速建连又断开,
wait_timeout设得太大(比如默认 8 小时)会导致线程池迅速被占满,新合法请求进不来 - 更危险的是:back_log 堆积本身不消耗 MySQL 线程,但一旦被 accept() 进来,就立刻占用一个线程——如果后续认证或初始化失败(如密码错、账号不存在),该线程仍会短暂存活,加剧拥塞
- 真正要防的不是连接数,而是连接质量:配合
connection_control插件限制高频失败登录,用max_connections和wait_timeout = 60控制空闲连接生命周期
容易被忽略的依赖项
back_log 调整后不生效,90% 是因为这几个点没对齐:
-
skip-name-resolve没开:DNS 解析延迟会让连接卡在 auth 阶段,看似是 back_log 不够,实则是单个连接处理太慢 - 防火墙或云厂商 SLB 重置了 TCP 连接(如超时 60 秒断连),客户端重试逻辑又激进,导致大量半开连接冲击 back_log
- MySQL 启动时加载了冲突插件(如
--plugin-load-add=connection_control=OFF),间接让连接控制类参数失效,放大 back_log 压力 - 监控只看
Threads_connected,却忽略了Threads_created每秒飙升——这是 back_log 溢出后客户端反复重试的典型信号
back_log 是个窄口径参数,它只解决“连接请求抵达 MySQL 门口时能不能排队”的问题。门开了,里面有没有人接待、接待效率如何、会不会被恶意占座,得靠 wait_timeout、connection_control、max_connections 和代理层规则一起管。











