一次 MySQL 远程连接超时问题的排查与解决

作者 lucy · 2026-04-11

⚠️ 声明:本文相关内容仅供参考,实际效果因场景不同可能差异很大,请结合自身情况判断,谨慎参考。

背景

项目采用前后端分离架构,后端服务与数据库独立部署。日常开发联调阶段一切正常,但系统正式上线运行一段时间后,开始出现偶发的数据库连接失败问题,具体表现为前端请求偶尔报错 Connection refusedConnection timed out,重启后端服务后问题消失,但隔几天又会复现。

问题描述

错误日志典型特征如下:

# 错误类型一:连接被拒绝
java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=XXX.XXX.XXX.XXX)(port=3306)(protocol=tcp)
Caused by: java.net.ConnectException: Connection refused

# 错误类型二:连接超时
java.sql.SQLNonTransientConnectionException: Connection timed out
Caused by: java.net.SocketTimeoutException: Connect timed out

排查过程

第一步:检查 MySQL 连接数

-- 查看当前所有连接数
SHOW STATUS LIKE 'Threads_connected';

-- 查看最大连接数
SHOW VARIABLES LIKE 'max_connections';

-- 查看当前连接详情
SHOW PROCESSLIST;

-- 结果:连接数远未达到上限,排除连接池满的情况

第二步:检查数据库服务器资源

# 检查 CPU、内存、磁盘
top
free -h
df -h

# 检查端口监听
netstat -tlnp | grep 3306

# 结果:服务器资源正常,MySQL 端口正常监听

第三步:检查防火墙与安全组

这是最容易忽略的环节。很多「偶发性连接超时」实际上是因为:

  • 云服务器安全组规则:只开放了特定 IP 段,数据库端口未对所有来源开放
  • MySQL 自身防火墙iptables 或云服务商网络安全组拦截了非白名单 IP
  • 连接数上限:部分云平台对基础配置账号有并发连接数限制
# 检查防火墙规则(Linux)
iptables -L -n | grep 3306

# 检查允许连接的 IP 白名单
# MySQL 内部 host 表:
SELECT user, host FROM mysql.user WHERE user='your_app_user';

-- 结果:host=localhost,远程连接被 MySQL 自身权限拒绝

第四步:排查连接池泄漏

# Druid 连接池配置建议(application.yml)
spring:
  datasource:
    druid:
      # 建议配置
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 60000          # 获取连接最大等待时间(ms)
      time-between-eviction-runs-millis: 60000   # 清理线程运行间隔
      min-evictable-idle-time-millis: 300000      # 最小空闲时间
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false

解决方案

方案一:开放数据库远程访问权限(不推荐用于生产)

-- 为应用账号开放远程访问(仅测试环境使用)
GRANT ALL PRIVILEGES ON your_database.* TO 'app_user'@'%' IDENTIFIED BY 'YourStrongPassword';
FLUSH PRIVILEGES;

-- 生产环境建议指定精确 IP
GRANT ALL PRIVILEGES ON your_database.* TO 'app_user'@'APP_SERVER_IP' IDENTIFIED BY 'YourStrongPassword';
FLUSH PRIVILEGES;

方案二:使用 SSH 隧道连接(推荐生产使用)

# 在应用服务器建立 SSH 隧道
ssh -L 3307:127.0.0.1:3306 -N -f user@db-server

# 应用配置连接到本地 3307 端口
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3307/your_database?useSSL=true

方案三:使用云数据库内网连接(最佳方案)

将数据库和应用服务器部署在同一私有网络(VPC)内,使用内网地址通信,完全避免公网暴露和防火墙问题。

# 应用配置使用内网地址
spring:
  datasource:
    url: jdbc:mysql://10.0.0.8:3306/your_database?useSSL=false
    # 10.0.0.8 是云数据库的内网地址

经验总结

  1. 生产环境禁止数据库端口直接暴露在公网。即使加了密码,端口暴露本身就存在被暴力破解和扫描的风险。

  2. 优先使用 VPC 内网连接,内网延迟更低、更安全。

  3. 连接池一定要配置空闲连接清理test-while-idle),防止连接被服务端关闭后客户端仍持有死连接。

  4. 偶发性连接问题大概率是连接池泄漏或服务端空闲连接超时,重点检查双方的超时配置是否匹配。

⚠️ 再声明:本文相关内容仅供参考。生产环境数据库安全配置请咨询专业 DBA,不同云服务商网络架构配置方法可能有差异。

发表评论

苏ICP备18039580号-2