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

做后端开发的同学,十有八九会遇到”本地连数据库没问题,部署到服务器就报错”的情况。最近在一次项目部署中,就遇到了远程 MySQL 连接超时的问题,从定位根因到最终解决,记录一下完整过程,供有类似问题的同学参考。

一、问题现象

项目使用 Java + 数据库连接池框架部署,远程 MySQL 部署在一台阿里云服务器上。本地开发时连接正常,部署到测试环境后日志中不断出现如下错误:

com.mysql.cj.jdbc.exceptions.CommunicationsException:
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.

连接池初始化失败,应用启动不起来。超时时间设置的是 10 秒,每次都是跑到 10 秒直接抛异常,说明问题不在代码,而在网络或数据库配置层面。

二、排查步骤

第一步:确认网络可达

最基础的一步,先从部署机器上 ping 一下数据库服务器 IP:

ping -c 4 43.142.208.230

结果:能 ping 通,网络层没问题。

第二步:确认端口可达

nc -zv 43.142.208.230 3306

或者:

telnet 43.142.208.230 3306

结果:连接被拒绝。这说明数据库端口没有对外暴露,或者数据库服务没有监听外部连接。

第三步:检查云服务器安全组

在阿里云控制台检查安全组配置,确认 3306 端口已对内网/指定 IP 开放。安全组是最容易被忽视的地方,很多云服务器默认只开放了 22 和 80 端口。

✅ 添加规则:允许 TCP 3306 端口,来源为应用服务器 IP 段。

第四步:检查数据库配置文件

登录数据库服务器,检查配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf(Debian/Ubuntu)或 /etc/my.cnf(CentOS):

[mysqld]
# 默认只监听本地,远程无法连接
bind-address = 127.0.0.1

# 修复方法:改为 0.0.0.0 或服务器实际 IP
bind-address = 0.0.0.0

这一步是 MySQL 远程连接最常见的坑——bind-address 默认值是 127.0.0.1,只允许本地连接。

第五步:检查用户权限

登录 MySQL,查看用户表:

mysql -u root -p
SELECT user, host FROM mysql.user WHERE user = 'your_user';

发现该用户 host 字段值为 localhost,只能从数据库本机登录,远程根本无权访问。

-- 创建允许远程访问的用户,或修改已有用户
CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON your_db.* TO 'your_user'@'%';
FLUSH PRIVILEGES;

⚠️ 生产环境建议将 % 替换为具体应用服务器 IP,而不是全开。

第六步:处理 SSL 连接问题

应用代码中数据库连接字符串类似这样:

jdbc:mysql://43.142.208.230:3306/your_db?useSSL=true&serverTimezone=UTC

如果数据库服务器没有配置 SSL 证书,需要显式关闭 SSL 或修改为 useSSL=false。在连接池中还需额外配置:

# 以常见连接池为例
spring.datasource.hikari.extra-ssl=false
spring.datasource.hikari.sslMode=DISABLED

否则可能出现”Unable to verify SSL certificate”之类的问题。

三、最终连接字符串

jdbc:mysql://43.142.208.230:3306/your_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&connectTimeout=30000&socketTimeout=60000

其中关键参数:

  • useSSL=false:内网环境关闭 SSL 验证
  • allowPublicKeyRetrieval=true:允许服务端返回公钥,避免特定版本报错
  • connectTimeout=30000:连接超时 30 秒,给足时间
  • socketTimeout=60000:Socket 读写超时 60 秒

四、验证结果

重启数据库服务:

sudo systemctl restart mysql

再从应用服务器测试连接:

mysql -u your_user -p -h 43.142.208.230 -D your_db

✅ 连接成功!应用也能正常启动并获取数据库连接了。

五、总结

这次问题的根因是三方面叠加:

  1. 云服务器安全组:端口未开放 → 网络层拒绝
  2. MySQL bind-address:只监听本地 → 远程协议层拒绝
  3. 用户 host 权限:用户无远程访问权限 → 认证层拒绝

三层检查缺一不可。建议在项目部署文档中明确写清数据库初始化脚本的权限配置,不要依赖手动操作,避免下一个项目重复踩坑。

另外,连接池的超时参数要根据实际网络状况调整,内网环境可以适当放宽,但对外暴露的接口务必控制好超时时间,防止资源耗尽。

⚠️ 声明:本文相关内容仅供参考,实际操作请根据具体业务场景和系统环境进行调整,生产环境任何配置变更请提前做好备份和评审。

发表评论

苏ICP备18039580号-2