别只改max_connections,它只是最后一道闸门,不是解药;真正卡住高并发的往往是系统级限制、连接堆积或应用未释放连接,调到5000仍报ERROR 1040是常态。

直接结论:别只改 max_connections,它只是最后一道闸门,不是解药。 真正卡住高并发的,往往是系统级限制、连接堆积、或应用没释放连接——调到 5000 还报 ERROR 1040: Too many connections 是常态。
怎么查当前到底用了多少、上限设了多少
连进 MySQL 后立刻执行这两条:
-
SHOW VARIABLES LIKE 'max_connections';—— 看你“理论上最多能接几个” -
SHOW GLOBAL STATUS LIKE 'Max_used_connections';—— 看历史上“真同时用过最多几个”
两者比值长期低于 0.3,说明 max_connections 设太高,白占内存;超过 0.9 就得动手了。注意:Threads_connected 是当前实时连接数,但很多是 Sleep 状态,不能只盯它。
临时改 vs 永久改,为什么改了配置文件还不生效
临时改用 SET GLOBAL max_connections = 2000;,命令一敲就生效,但 MySQL 重启就回滚。永久改必须写配置文件,但常见失效原因不是写错,而是:
- 配置文件位置不对:
/etc/my.cnf、/etc/mysql/mysql.conf.d/mysqld.cnf、甚至/usr/etc/my.cnf都可能被读取,用mysqld --help --verbose | grep "Default options"确认实际加载路径 - systemd 服务限制卡死:CentOS 7+/Ubuntu 16.04+ 默认
LimitNOFILE=4096,而max_connections> 1024 时,MySQL 会自动按比例下调(比如你设 2000,实际只生效 214) - 必须在对应 service 文件(如
/usr/lib/systemd/system/mysqld.service)的[Service]段加:LimitNOFILE=10000和LimitNPROC=10000,再运行systemctl --system daemon-reload,最后重启
验证是否真生效:cat /proc/$(pgrep mysqld)/limits | grep "Max open files",soft limit 必须 ≥ 你设的 max_connections 值。
设多大才合理?别只看数字,要看内存和真实并发
max_connections 不是越大越好。每个连接基础内存开销约 256KB~1MB(取决于 thread_stack、sort_buffer_size 等),设 3000 连接,光线程栈就吃掉 1GB+。更关键的是:
- 真正影响响应速度的是
Threads_running(当前正在执行 SQL 的线程数),它通常只有几十个,和总连接数无关 - 硬上限是 16384,设成 20000 会被 MySQL 自动截断
- 必须同步调高
wait_timeout(默认 28800 秒),线上建议压到 300~600 秒,否则大量Sleep连接堆积不释放 - 应用层必须配连接池(如 HikariCP 的
maximumPoolSize)且与max_connections匹配,否则池子开太大,后端扛不住;开太小,前端排队
最常被忽略的一点:调完参数后,不查 information_schema.PROCESSLIST 或 SELECT user, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY user;,根本不知道是谁在疯狂建连接或忘了 close。


















