
都2025年了居然还有人问我“MySQL最多能有多少连接”。说真的这个问题在社区里隔三差五就会出现一次但每次回答完我都觉得提问的人可能只想知道一个数字却完全没搞明白数字背后那条“连接链”是怎么一步步断掉的。今天我不打算只甩一个配置项给你而是想顺着“连接数”这条线把最大连接数、并发瓶颈、线程模型、连接池参数这些掰开揉碎讲一遍。你照着这篇文章去排查大概率能定位到你系统真正的卡点在哪。先说结论如果单看MySQL自身的配置max_connections的最大值上限在MySQL 5.7及8.0里通常是10000010万但实际上绝大多数业务服务器根本扛不到这个数。真是场景里300到1000才是更常见的合理区间。而且连接数只是“你能开多少个门”真正让你死机的是“开门后同时有多少人涌进来办事”也就是并发查询数量。搞混这两个概念排查方向从一开始就是歪的。1. 连接数的本质一条TCP链路在MySQL内部经历了什么1.1 每次“连接”不仅是MySQL的事很多人理解“MySQL连接数”就是数据库开几个会话窗口其实不完整。MySQL的连接是标准的TCP连接从客户端发起connect()开始整条链路上至少要经过客户端socket创建与TCP三次握手MySQL线程接收连接分配thread_id初始化会话上下文校验用户名密码和主机白名单执行max_connections计数检查如果超过上限直接报Too many connections这里有个隐性问题大部分新手压根没意识到“连不上MySQL”大概率不是MySQL拒绝了你而是操作系统先拒绝了TCP连接。我见过太多事故现场max_connections明明还有富余但应用就是报Cant connect最后查出来是/etc/security/limits.conf里的nofile文件描述符限制太小或者tcp_max_syn_backlog溢出把连接请求堵在了内核层面。所以讨论“最多能有多少连接”实际上要同时看三层MySQL自身的max_connections操作系统层面对进程fd数量和TCP连接队列的限制物理内存是否支撑得起这么多线程和会话缓存1.2 max_connections到底能设多大max_connections是一个动态变量也就是说在运行中可以直接SET GLOBAL修改不需要重启实例。默认值在MySQL 5.7为1518.0也保持了这个传统。这个数值显然太小因为它面向的是比较保守的默认场景。你可以通过以下SQL查看当前值SHOW VARIABLES LIKE max_connections; SHOW STATUS LIKE Threads_connected; SHOW STATUS LIKE Max_used_connections;Max_used_connections记录的是实例启动以来达到过的最大连接数峰值这个比Threads_connected更能反映真实水位。很多运维只看当前连接数结果白天业务高峰已经冲到2000了他还在那说”我们的连接数才几十“那当然是被瞬时波动掩盖了。把max_connections调到10万有没有意义我直接说对99%的项目没有意义。MySQL每开一个连接就要创建一个线程connection-per-thread模型每个线程默认thread_stack是256KB再加上会话级内存几百个线程同时活跃的时候内存和上下文切换开销就已经很可观了。你用10万连接数做配置内存可能直接被打爆。1.3 别把“连接数”当并发能力这里必须强调一个经典误区连接数不等于并发能力。并发能力是指同一时刻有多少请求正在执行SQL并占用CPU/磁盘IO连接数只是会话的数量。很多连接建立后处于Sleep状态啥活没干就是占着一个坑位。一个600连接的库如果其中550个都在Sleep真实并发可能只有50。这时候你把max_connections翻倍大概率解决不了性能问题反而让线程堆积得更严重。真正要看的是Threads_running这个状态值代表正在执行语句的线程数。如果Threads_running居高不下连接数再怎么调也是白搭。2. 查问题先查链路一个“连接数爆了”的真实定位过程2.1 从一次线上事故说起去年有个客户找我说业务高峰期MySQL直接报Too many connections应用批量失败。他当时的max_connections是500已经觉得不小了。我先让他做了一件事mysql -u root -p -e SHOW STATUS LIKE Threads%; mysql -u root -p -e SHOW VARIABLES LIKE max_connections;结果很有意思Threads_connected卡在450左右Threads_running却只有20多。这说明问题根本不是连接数硬件上限触顶而是大量连接滞留不断累积导致坑位被占满。接着查了SHOW FULL PROCESSLIST发现大量Sleep状态的连接来自同一个业务IPKeepAlive参数没配好连接处于假死状态。客户端以为连接还活着实际上服务端早就断了但断开的连接没有及时被清理于是不断新建连接、再滞留、再新建形成一个恶性的连接泄漏循环。2.2 逐步排查连接泄漏的有用脚本排查连接问题我最常用的三连操作-- 1. 按用户分组看连接占用 SELECT user, host, db, COUNT(*) AS cnt FROM information_schema.processlist GROUP BY user, host, db ORDER BY cnt DESC; -- 2. 按来源IP分组看连接分布 SELECT SUBSTRING_INDEX(host, :, 1) AS client_ip, COUNT(*) AS cnt FROM information_schema.processlist GROUP BY client_ip ORDER BY cnt DESC;通过这个脚本很快就能看到哪个应用、哪个IP在疯狂占连接。很多情况下不是数据库的问题而是应用层的连接池配置有漏洞。2.3 临时跟永久调整的连接数如果线上已经告警可以应急调大SET GLOBAL max_connections 1000;但要特别注意这个操作只对后续新连接生效已在排队等待的请求依然会失败。另外SET GLOBAL修改的是运行时值重启MySQL之后会重新回到配置文件里的值。想要永久生效还得改my.cnf或my.ini里的max_connections项然后重启。这里多提一句千万不要在大促前临时调这个还不通知开发。我曾经见过有人把max_connections从500调到5000结果业务方连接池的maximumPoolSize也跟着乱跳瞬间五千个线程抢锁数据库没崩应用先崩了个稀里哗啦。3. 连接数相关参数的正确打开方式3.1 不只是max_connections这些参数连坐连接问题从来不是单一参数能解决的和它关联的参数还包括参数名作用典型设置max_connections最大连接数上限300~1000max_user_connections限制单个用户最大连接数按应用隔离wait_timeout非交互连接超时秒数60~120interactive_timeout交互式连接超时秒数120~300thread_cache_size线程缓存数量与连接峰值相关back_log连接请求排队数128~512max_execution_time慢查询熔断时间8.0按需设置wait_timeout特别值得说。默认值在MySQL 8.0是28800秒也就是8小时。如果应用侧没有合适的连接回收机制大量空转Sleep连接能在这个时间里一直占着坑。我一般建议明确设置成60秒甚至更短配合应用层连接池的validationInterval去自动剔除失效连接。为什么要让数据库主动断连接而不是让应用池来管因为很多时候应用框架的线程模型并不可控。比如某些老PHP应用每个请求都会直连MySQL又没有连接池概念请求结束如果不显式关闭连接就滞留在MySQL端。这时候wait_timeout就是最后一道安全生产线。3.2 通过系统状态判断你到底缺不缺连接不看SHOW STATUS就调参数等于蒙眼开车。我建议每次调优前先记录这几项-- 历史达峰连接数 SHOW GLOBAL STATUS LIKE Max_used_connections; -- 当前连接数 SHOW GLOBAL STATUS LIKE Threads_connected; -- 正在运行的线程数真实并发 SHOW GLOBAL STATUS LIKE Threads_running; -- 历史被拒绝的连接次数 SHOW GLOBAL STATUS LIKE Connection_errors_max_connections;Connection_errors_max_connections只要不是0就说明曾经发生过因为连接数上限而拒绝连接的情况哪怕影响时间只有几十毫秒。这个指标很隐蔽但它是“已经碰过天花板”的铁证。如果Max_used_connections长期低于max_connections的70%而业务还老是卡顿问题多半不在连接数上要去查SQL效率、锁等待、IO瓶颈。相反如果你发现Max_used_connections已经非常接近max_connections但同时Threads_running很低那就说明连接池配置过于激进应用创建了太多闲置连接该收的是应用侧。4. 连接池不是“越大越好”Druid、HikariCP与MySQL的爱恨情仇4.1 HikariCP为什么默认只有10很多Java开发者第一次看到HikariCP的默认配置都会愣一下maximumPoolSize默认10这也太小了吧。我连接数都调到1000了连接池才10个连接岂不是浪费这里得讲清楚一个底层权衡。连接池里的连接是复用的每个池化连接在一次SQL执行完毕之后并不关闭而是归还池中。10个连接如果每个查询都秒级返回理论上每秒钟能处理远超10个请求因为请求是排队轮流使用这10个连接。但如果你把连接池调到200而数据库max_connections只有500再有三个应用实例同时连这个库每个实例200就是600直接突破数据库上限。这种“连接池叠加效应”是分布式架构下最常见的连接数失控原因。4.2 连接池参数要跟上max_connections的节奏我见过的最佳实践是数据库max_connections按“所有客户端连接池上限之和再乘以1.5冗余”来设计。比如你有3个Java服务实例每个连接池maximumPoolSize100那么数据库至少预留450到600的连接上限。同时再监控一下认证连接数不能让某个实例把池子撑爆。Druid作为国内使用率很高的连接池配置上有一个关键参数容易被忽略spring.datasource.druid.test-while-idletrue spring.datasource.druid.validation-querySELECT 1开启这个之后Druid会定期检查空闲连接是否可用如果MySQL那边因为wait_timeout把底层连接断掉了连接池能及时发现并剔除应用就不会拿到一个表面正常实际已经坏掉的连接。我之前排查过一个诡异问题应用启动没问题但只要放置一晚上第二天早高峰第一次请求必报Communications link failure重启应用就好。典型原因就是连接池里的连接被MySQL断了但连接池不知道继续分发不可用连接。针对这种情况除了开启空闲检测还可以把连接池的connectionTimeout调低配合MySQL的wait_timeout双向掐断死连接。4.3 连接池参数速查表这里给一份我实践中验证过比较稳的连接池基线配置基于Spring Boot 2.x HikariCPspring.datasource.hikari.minimumIdle5 spring.datasource.hikari.maximumPoolSize50 spring.datasource.hikari.connectionTimeout30000 spring.datasource.hikari.connectionTestQuerySELECT 1 spring.datasource.hikari.idleTimeout60000 spring.datasource.hikari.maxLifetimeTime1800000 spring.datasource.hikari.validationTimeout5000注意maxLifetimeTime应该小于MySQL的wait_timeout比如MySQL的wait_timeout是8小时那maxLifetimeTime控制在30分钟以内比较稳妥留出足够余量避免池内连接被数据库单方面回收。5. 直连MySQL还是走中间件连接数的分岔路5.1 单机直连的场景边界如果你只是一个小项目数据库单实例应用不超过三五个直连MySQL完全没问题。此时max_connections设个300到500就够用了。关键是应用层的连接池必须控制好别每个服务各自为政往大了调。5.2 引入Proxy后的连接收敛流量一大、实例一多直连模式就会暴露出两个问题连接数不可控、故障切换困难。这时候就轮到中间件出场了比如ProxySQL、MyCat或者云厂商的数据库代理。中间件统一收口数据库连接应用只连中间件数据库连接数不再跟实例数量相乘增长而是被中间件按需分配。我之前一个客户五十多个微服务实例直连MySQL每个实例默认连接池20理论上最大并发连接数就是1000数据库直接跪了。后来把应用全部切到ProxySQL数据库max_connections其实没怎么变但中间件把真实连接收敛到200左右因为很多服务其实用不了那么多并发连接收口后效果立竿见影。5.3 用缓存扛连接风暴再拓展一步连接数爆炸的时候很多时候根本不该去连数据库。接口热点数据如果打到Redis上就能扛住连接数压力自然就降下来了。我有个原则同一个热点数据能缓存就缓存MySQL连接是稀缺资源不该让每个请求都去消耗一次往返。6. 连接数问题排查的常见坑和速查表6.1 报错信息到底在说什么连接类报错最容易让人迷惑这里整理几个最常见的报错信息真正含义初步动作Too many connections连接数达到max_connections上限查Threads_connected、Max_used_connections紧急调大或杀SleepCant connect to MySQL server on x.x.x.x (10060)网络不通或防火墙拦截检查防火墙、安全组、网络连通性Cant connect to MySQL server on x.x.x.x (10061)端口被拒绝或mysqld未启动确认MySQL进程监听状态Communications link failure连接被远端中断排查连接池、wait_timeout、网络链路ERROR 1129 (HY000): Host is blocked连接失败次数过多被临时封禁清空host_cache并挂载防火墙策略特别说下Host is blocked这个问题出现的概率不高但很致命如果你的某台客户端机器连接失败次数连续超过max_connect_errors默认100MySQL会在内存里把这个主机标记为阻塞之后所有来自该IP的连接都会被直接拒绝。解决办法是FLUSH HOSTS清缓存然后去应用侧排查为什么老是连失败。6.2 那Sleep连接怎么清理很多同学看到一堆Sleep连接就开始杀这是不对的。Sleep连接本身无害真正有害的是连接池或长连接机制没有正确复用它们导致连接无限堆积。你可以做以下动作如果确认是某个无用的会话直接KILL id如果Sleep连接数量持续异常先查应用侧的连接池回收逻辑如果wait_timeout设置得过大调小它让MySQL自动清理。我的经验是先问一句这些Sleep连接从哪里来为什么新连接不断增加而不是复用如果这个问题不解决你杀掉的连接马上会被新建连接补回来治标不治本。6.3 一张图理清连接数排查顺序这不是流程图但我习惯按这个顺序排查连接问题看Max_used_connections有没有触顶看Threads_connected当前水位看Threads_running真实并发查PROCESSLIST找异常来源检查连接池是否正常回收确认OS文件描述符限制和TCP队列没有成为瓶颈这六步做完基本能把90%的假“连接数爆炸”排除掉剩下的才轮到真正需要动max_connections参数的场景。7. 实操案例把max_connections从200平稳调到20007.1 场景还原客户的一个电商系统平时并发不高但每逢活动就会瞬时涌入大量连接。因为活动前的压测报告显示连接峰值500左右所以客户当时把max_connections设成了1000想着足够冗余了。结果活动开始半小时后开始报Too many connections连接数进度瞬间顶满。我先查了Threads_connected和Threads_running发现连接数涨到900的时候Threads_running才70。由此判定是连接建立过快、连接池回收不及时而非真实并发太高。当时在活动期间我建议的处理是两步走-- 第一步将等待空闲时间调低让Sleep连接快速被回收 SET GLOBAL wait_timeout60; SET GLOBAL interactive_timeout120; -- 第二步临时调大连接数上限扛过峰值 SET GLOBAL max_connections2000;7.2 为什么先调wait_timeout而不是直接调max_connections因为活动期间的连接数暴涨大部分是客户端在大量新建连接但连接执行完SQL后不及时关闭。wait_timeout缩短后MySQL可以更快地把这些空连接断掉从而腾出坑位。直接调max_connections虽然也能立竿见影允许更多连接进来但会让物理资源被大量Sleep连接白白占住后续其他查询性能反而会下降。活动结束后我把配置写回了my.cnf[mysqld] max_connections 1000 wait_timeout 60 interactive_timeout 120 thread_cache_size 128然后重启MySQL让配置永久生效。重启前我特意保留了重启前的状态指标重启后对比发现Max_used_connections在下一轮活动中稳定在600到700而Threads_running依然保持在100以内说明连接质量明显变高了。7.3 案例复盘我想说的话这个案例的环境不算复杂但很典型。要我总结的话连接数问题的本质不是“调大就能扛”而是“杜绝无意义连接占用资源”。连接池、超时时间、应用生命周期管理和MySQL参数必须四管齐下缺一环都容易踩坑。8. 最后再分享两个小技巧第一监控脚本里一定要加一项Threads_connected / max_connections的比率告警我通常设置在80%预警、90%触发紧急告警。这个指标比单纯看QPS更能提前暴露连接池耗尽风险。第二如果你用MySQL 8.0可以试试把max_execution_time配到查询级别给每条SQL设定一个最大执行时间。这样即使连接数没有爆每条SQL也不会无限占着线程资源不出活变相提高了连接利用率。MySQL连接数这个问题表面上一个配置项就能回答实际上牵涉到操作系统、网络、应用框架和数据库线程模型的完整链路。下次再有人问“最多能有多少连接”你可以告诉他官方上限10万但真正决定你系统活不活得下来的是你怎么规划连接的使用方式。