Druid连接池create connection error报错排查与调优指南

发布时间:2026/10/20 17:14:17
Druid连接池create connection error报错排查与调优指南 看到日志里打出com.alibaba.druid.pool.DruidDataSource - create connection error这一行时很多人的第一反应是把报错往群里一甩“连接池有问题了怎么办”。先别慌。这个报错字面上说的是Druid 在创建一个新的物理数据库连接时失败了。它可能出现在服务启动阶段也可能出现在运行期某条连接被回收之后、再次重建的过程中。无论哪种情况都意味着应用和数据库之间那条链路没有正常建立起来。这个报错看着只是日志里的一行实际影响范围却不小。启动阶段出现它服务可能直接起不来运行期出现它紧接着往往就是接口超时、数据库连接耗尽、实例持续重试严重点还会拖垮同一批机器。尤其微服务场景下各方实例同时尝试重建连接数据库压力会在几秒内被放大好几倍。后端开发、运维和 DBA 遇到这个报错都不少见排查思路其实很明确链路、账号、连接配置、连接池参数一层层查下去大多数情况半小时内就能定位。1. 读懂报错本身Druid 到底是在抱怨什么1.1 创建连接这个动作发生在哪里DruidDataSource是 Druid 连接池的核心类它的职责是维护一批可复用的数据库连接。应用不再直接向数据库建连而是向连接池借用连接。既然要维护“池”就需要在两种时机新建连接池初始化时也就是initialSize配置的数量运行期连接不够用时在不超过maxActive的前提下额外创建。“create connection error” 这条日志就是 Druid 在这两个时机里尝试建立物理连接失败后打出来的。注意它本身不是业务异常而是连接池内部错误日志。业务侧看到的是另一个表现比如获取连接超时、CannotGetJdbcConnectionException、Connection is not available之类。很多人只盯着业务异常排查反而忽略了这个最直接的原因日志。com.alibaba.druid.pool.DruidDataSource - create connection error, url: jdbc:mysql://数据库IP:3306/demo?xxx, errorCode 0, state 08001 java.sql.SQLException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.我习惯先把这一整段堆栈拷出来重点看三处url后面到底连的是哪个库errorCode和state是什么最底层的Caused by是哪一类异常。这三处信息基本能锁定排查方向。1.2 堆栈里的状态码和底层异常没那么难懂按 JDBC 规范state 08001表示“无法建立连接”这一类错误28000表示认证失败42000多数是指定的库或对象不存在。不同驱动打印的errorCode含义略有差异但方向是对的。真正决定排查方向的是Caused by那一层。常见写法是Communications link failure、Connection refused、Access denied for user、Unknown database、Too many connections、connect timed out。每一种背后对应的原因差别很大排查动作也完全不同。如果连这一层都没看直接去调连接池参数等于还没分诊就开药。1.3 出现频率和业务流量的关系还有一种比较隐蔽的情况日志里只有零星几条create connection error但业务看起来一切正常。这通常发生在连接池运行期某条空闲太久的连接被中间的网络设备悄悄断掉Druid 尝试复用时才发现坏了于是新建连接时打了一条错误。因为池里还有其它可用连接业务没有感知。这种“昙花一现”的报错不需要过度紧张但要留意频率。如果一分钟出现几十上百条那一定是链路或后端资源出了真问题。2. 由外到内排查网络、数据库服务、账号权限三层验证2.1 先确认网络链路通不通连接建立失败的第一大类原因是网络链路问题比如数据库地址不可达、端口被防火墙拦截、云平台安全组放行策略不对、跨网段路由不通。我建议的检查顺序很简单先用工具判断“通不通”再判断“通但协议不对”。命令行这几步可以直接照抄# 第一步看IP能不能通 ping 数据库IP # 第二步看端口有没有监听能连上TCP说明链路层是通的 telnet 数据库IP 3306 # 没有telnet时用nc nc -vz 数据库IP 3306 # 直接用mysql命令行完成后端真实协议的握手测试 mysql -h 数据库IP -P 3306 -u用户名 -p密码 -e select 1如果 ping 不通看是否 IP 段写错、网络策略变更、目标机器宕机。如果 ping 能通但 telnet 不通大多是防火墙或安全组把端口挡了。如果 telnet 能通但 mysql 命令连不上就要往数据库服务和账号方向查。这里有个特别容易踩的坑同一套代码在测试环境好好的上了生产就报连接失败。不少时候不是代码的问题而是生产数据库在云平台安全组里漏配了应用服务器网段的入方向规则或者数据库白名单只放行了一部分机器。新扩容的实例自然连不进去。2.2 数据库服务本身是否还健康链路通了再看数据库进程是否活着、连接数是否还充足。数据库服务如果刚重启过或者 max_connections 设置得很小同样会报创建连接失败。登录数据库机器后先看进程和端口# 以 MySQL 为例 ps -ef | grep mysqld ss -lntup | grep 3306再进数据库查连接数状态SHOW VARIABLES LIKE max_connections; SHOW STATUS LIKE Threads_connected; SHOW PROCESSLIST;Threads_connected如果长期贴着max_connections新连接自然建不进来报错信息里往往带着Too many connections。这时候先别急着扩连接数先查清楚谁把连接占满了。很多情况下是某条慢查询卡住了或者某个服务忘了归还连接把连接池和数据库的连接一起拖爆。补充一个容易忽略的点MySQL 8 里还有个max_connections之外的隐藏限制max_user_connections。如果某个业务账号的连接数到了上限即使全局还有余量也一样建连失败。排查时可以顺便看下这个参数。2.3 账号权限和认证方式核对链路通了、数据库也正常那就该怀疑账号。拿着连接串里的用户名、密码手动在命令行试一下能最快复现认证问题。-- 查看账号权限 SHOW GRANTS FOR 业务账号来源IP; -- MySQL 8 不推荐直接改认证方式但需要确认驱动兼容 SELECT user, host, plugin FROM mysql.user WHERE user业务账号;常见认证问题有两类。一类是密码错误或账号 host 限制报Access denied for user另一类是 MySQL 8 默认的caching_sha2_password认证插件和旧的驱动不兼容报Unable to load authentication plugin caching_sha2_password。后面这种处理方式很简单升级数据库驱动到 8.x或者把账号认证改回mysql_native_password。我建议优先升级驱动因为改认证方式只是绕路。为了更直观把典型的底层异常和对应原因整理成一张对应表排查时照着对。底层异常关键字大概率原因优先排查方向Communications link failure网络中断、DB重启、连接被中间设备回收链路、DB状态、空闲连接回收策略Connection refused端口未监听、防火墙拒绝DB进程、iptables、安全组connect timed out网络不通、路由丢包、SYN backlog满路由、防火墙、DB负载Access denied for user账号密码错误、host限制账号权限、密码、host白名单Unknown database库名不对或不存在连接串库名、DB实例列表Too many connections数据库连接数打满max_connections、慢查询、连接泄漏Unable to load authentication plugin驱动与认证插件不兼容升级驱动、账号认证方式3. 连接串和驱动配置报错里最容易被人忽视的一环3.1 URL 里的每个参数都可能埋雷一个完整的 JDBC 连接串长这样jdbc:mysql://127.0.0.1:3306/demo?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseconnectTimeout3000socketTimeout30000allowPublicKeyRetrievaltrueconnectTimeout和socketTimeout这两个参数尤其值得注意。前者是建立 TCP 连接的超时时间后者是通信超时时间。有些环境下网络本身有延迟默认值又偏保守于是建连阶段直接超时报错。我见过不止一次把connectTimeout从默认值调到 3000 毫秒报错就不再出现。但反过来也要小心别为了掩盖网络问题把超时调得过大否则应用会长时间阻塞在获取连接上。serverTimezone是另一个高频埋雷点。MySQL Connector/J 6.0 以后必须显式指定时区否则会报The server time zone value相关错误。连接串里写Asia/Shanghai是最直观的如果需要兼容 URL 特殊字符可以用GMT%2B8这种编码写法。useSSLfalse属于开发环境下常见的配置。如果数据库端没有开启 SSL驱动默认尝试 SSL 握手反而会失败如果生产环境走的是安全内网明文传输风险也还可控。但生产上更规范的做法是明确数据库是否启用 SSL然后按实际情况配置而不是无脑加useSSLfalse。3.2 驱动版本要和数据库版本匹配驱动和数据库不匹配导致的创建连接失败属于比较隐蔽的一类。比如 MySQL 5.7 的库用了很新的 8.x 驱动绝大多数情况没事但某些特性、认证方式上会出幺蛾子。反过来MySQL 8.0 的库用 5.x 的驱动大概率直接报认证插件错误。我踩过的坑是某项目升级数据库到 MySQL 8 之后所有实例开始周期性报create connection error查了半天网络和账号都没问题最后发现是工程里依赖的mysql-connector-java还是 5.1.x。升级驱动后问题消失。所以排查到驱动这层时建议把驱动版本、数据库版本、连接池版本三者的兼容关系都列出来看。这个场景下最快的验证方式是在本地用一个最小的 Java 程序只加载驱动、建一个连接、执行select 1。能连上说明问题在连接池配置或环境连不上说明连接串、驱动、账号三者之间还有不合拍的地方。3.3 连接池初始化阶段和运行阶段要分开看很多人忽视了一个细节连接池启动时的初始化失败和运行期的重建失败配置上的应对方向完全不同。启动失败时initialSize个连接统统创建不出来Spring Boot 应用经常会直接启动失败报Failed to configure a DataSource。这时候哪怕后面数据库恢复了应用也没自动起来。运行期失败则多半是间歇性的日志会持续出现但服务还活着只是每次重建连接失败前会有一批请求受影响。针对这两种场景处理手段不同。启动失败需要在配置上给足超时和重试机会运行期失败则要重点排查空闲连接回收、网络设备空闲超时、数据库wait_timeout这类参数。4. 高并发场景下那些更隐蔽的建连失败4.1 数据库连接数被打满的连锁反应一个业务系统实例连接池配了maxActive20部署 30 个实例那理论上最多会向数据库建立 600 条连接。数据库的max_connections如果只有 500高峰期必然有实例建连失败。这不是 Druid 的问题是“容量规划”的问题。排查这类问题时我喜欢用一个粗算公式实例数量 × 单个实例 maxActive 必须远小于数据库max_connections保留 30% 左右的余量给管理连接、备份任务和其它临时需求。如果没有余量数据库一旦出现慢查询每条 SQL 占用的连接时间变长连接就“淤积”在数据库侧。这时新连接请求不断进来数据库忙于创建线程CPU 和内存压力飙升进一步加剧建连失败。整个链路会从“少量报错”演变成“大面积雪崩”速度往往快得吓人。4.2 空闲连接被静默踢掉之后的重建风暴这是我最想强调的一个场景。很多云环境或自建机房的网络设备会清理长时间空闲的 TCP 连接MySQL 服务端也有wait_timeout和interactive_timeout默认通常是 8 小时。连接池里的连接如果一直没被使用可能早已被对端关闭但应用侧完全不知道。等到请求高峰期来临连接池发现池里的连接不可用开始大量新建连接。新建连接时底层 TCP 握手、MySQL 认证需要时间这个过程中请求在等待数据库侧同时处理一堆新连接压力陡增。于是明明业务流量没有暴涨数据库却在几分钟内被连接风暴打高。应对思路有几个方向一是 Druid 连接池开启keepAlive让低于minIdle的空闲连接被主动保活二是合理设置timeBetweenEvictionRunsMillis让空闲连接能被周期性检查三是配合数据库侧把wait_timeout调到合理值避免连接被过早回收。这几项参数在下文会给出具体建议。4.3 多实例同时重启造成的“羊群效应”发布系统在批量滚动重启时所有实例几乎同一时间启动。每个实例的 Druid 初始化都会创建一批连接比如 30 个实例、每个初始化 5 条连接就是 150 条连接在同一秒涌向数据库。如果数据库规格不大很可能瞬间把连接数打满接着一批实例启动时报create connection error。这时候日志的“长相”是某次发布后多台机器同时报错。实际上数据库没有故障只是短时并发建连超过了它的承受能力。建议发布时尽量用分批滚动或者把应用的initialSize调小启动后再让连接池按需增长。Druid 本身支持初始化失败后的重试机制但重试间隔和数据源恢复速度相关不能指望它来处理“连接风暴”。4.4 数据库迁移或 DNS 变更后的长连接失效数据库迁移、实例切换、VIP 漂移之后IP 变了但连接池里的旧连接还指向旧地址。旧连接如果正好在这之后被使用就会报连接失败。这个报错的隐蔽性在于它不一定是持续性的而是断断续续的直到所有旧连接被淘汰、新连接全部替换完成。如果你刚做过数据库迁移或网络变更恰好开始出现create connection error优先怀疑长连接没有及时重建。解决方法是确认连接串里用的是否是稳定的域名而不是裸 IP同时在变更前通知开发侧重启相关应用让连接池能整体重建一套新连接。5. Druid 连接池参数调优照抄配置不如理解参数5.1 核心参数速查清单Druid 的参数很多但和“创建连接失败”强相关的就那么几个。先说清楚每个参数控制什么再给一套起步配置别直接复制到生产。参数含义调优倾向initialSize启动时预建的连接数不宜过大2~10 足够minIdle池中最低空闲连接数和 initialSize 保持一致即可maxActive最大活跃连接数结合数据库 max_connections 和实例数计算maxWait获取连接的最大等待时间毫秒3000~10000 常见过小容易误伤timeBetweenEvictionRunsMillis空闲连接检测周期30000~60000 常见minEvictableIdleTimeMillis连接最少空闲多久可被回收180000~300000 常见keepAlive对低于 minIdle 的连接执行保活建议开启validationQuery校验连接是否有效的 SQL简单查询如 SELECT 1testWhileIdle空闲检测时是否验证建议开启testOnBorrow借用连接时是否验证不推荐开启影响性能removeAbandoned自动回收泄漏连接慎用需配合超时时间避免误杀5.2 一套可参考的起步配置下面这套配置适合大部分中小型业务但不代表所有场景。配置时要结合自己的 QPS、SQL 耗时、数据库规格来调整。spring: datasource: druid: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 3000 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 keep-alive: true validation-query: SELECT 1 test-while-idle: true test-on-borrow: false test-on-return: falsemaxWait3000很多人不敢用怕高峰期线程都卡在等待上。其实这正是一个“快速失败”的机制拿不到连接就立刻失败让调用方走降级或重试而不是把线程全部堵死在连接池上。如果业务数据库响应普遍快3 秒足够。如果 SQL 本身经常超过 3 秒那问题不在连接池得先解决慢 SQL这个参数只是兜底。5.3 调参一定要避开的几个坑第一个坑是盲目把maxActive调大。连接池的maxActive不是越大越好。连接数上去后数据库侧每个连接都有内存和线程开销切太大反而加剧数据库压力最终导致更多建连失败。正确姿势是先压测出单实例需要的并发连接数再乘实例数对照数据库规格留余量。第二个坑是testOnBorrowtrue和validationQuery的组合被滥用。testOnBorrow虽然能在每次拿连接时都做校验但会额外产生一次查询在 QPS 较高时放大数据库压力。大多数场景下testWhileIdletrue配合保活机制就够了压根不需要每次借用都验证。第三个坑是忽略timeBetweenEvictionRunsMillis和数据库wait_timeout的配合。如果 Druid 的检测周期比数据库wait_timeout长空闲连接就可能先被数据库断掉检测还没开始执行。建议检测周期不要超过数据库wait_timeout的一半比如数据库wait_timeout28800时这个周期设 60000 就挺安全。第四个坑是removeAbandonedtrue以及相关联的removeAbandonedTimeout设置得过小。它会把“执行时间较长但还没结束”的连接当成泄漏连接强杀导致事务被中断代码里开着事务但连接已经回收到池中后面再用就出乱子。不要轻易开这个功能。6. 生产环境如何避免再次踩坑监控和预案6.1 连接池核心指标盯哪些等报错真的发生时再排查代价已经不小了。更稳的做法是把连接池的关键指标接到监控里。Druid 自带的统计能力在这一块做得比较完整Spring Boot 项目中可以通过 Druid 的监控页在开发环境查看生产环境建议接指标系统。重点指标就几个activeCount活跃连接数、poolingCount池中连接数、maxActive上限、connectErrorCount建连失败次数、waitThreadCount等待线程数、notEmptyWaitCount获取连接时发生等待的次数。其中connectErrorCount是直接反映“create connection error”的指标数值持续大于 0 就需要关注。waitThreadCount则能提前暴露连接池“不够用”的趋势比业务报错来得更早。6.2 建议接怎样的告警规则告警规则可以参考下面这套思路实际阈值按业务评估activeCount连续 5 分钟大于maxActive的 80%说明连接池快被占满。connectErrorCount在任意 5 分钟内大于 0且数据库网络没有变更期直接告警。数据库侧Threads_connected连续 5 分钟大于max_connections的 80%。应用侧出现获取连接超时的异常日志比例超过某个基线。新手容易犯的错是只盯应用不盯数据库。连接池指标只是“果”数据库的连接数、慢查询、CPU 才是“因”。真正想把问题从源头掐掉两边指标得对着看。6.3 故障预案和恢复演练报错出现之后恢复动作的先后顺序也会影响止损速度。我建议按这个顺序处理先确认数据库是否活着、连接数有没有打满再确认链路是否正常最后才考虑是否动连接池配置。很多人在数据库还没恢复时就去调应用参数怎么调都没用。另外可以主动做一轮“故障演练”。比如在测试环境把数据库重启观察连接池自动恢复需要多久或者在安全组临时取消某台机器的放行策略观察应用侧create connection error是否如期出现。这类演练能帮团队把排障动作变成肌肉记忆真出问题时不会手忙脚乱。根据我个人经验连接池报错里九成以上不是代码逻辑的问题而是链路、资源配额、连接配置这三件事没对齐。看到create connection error时别急着改代码先手动把select 1跑通再回去看参数思路顺了这类问题基本都能稳稳解决。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询