java.net.ConnectException: Connection refused报错的解决方法详解
作者:李少兄
前言:一个高频却常被误解的异常
在 Java 企业级应用开发中,无论是构建 Web 后端服务、微服务架构,还是进行数据集成与批处理任务,开发者几乎不可避免地会遇到如下异常堆栈:
java.net.ConnectException: Connection refused: connect
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:589)
at java.base/sun.nio.ch.Net.connect(Net.java:578)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:583)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:751)
...
该异常通常出现在尝试建立 TCP 连接时——例如通过 JDBC 连接 MySQL、调用 RESTful API、连接 Redis 缓存、或与消息队列(如 RabbitMQ、Kafka)通信。尽管其字面意思看似直白(“连接被拒绝”),但许多开发者在初次遭遇时仍会陷入困惑:是代码写错了?是网络不通?还是服务宕机了?
一、问题本质:操作系统层面的“拒绝”信号
1.1 异常来源并非 Java 虚拟机
首先必须明确:java.net.ConnectException 是 Java 对底层操作系统返回错误码的封装。当 Java 应用调用 Socket.connect() 方法时,JVM 会委托操作系统内核发起 TCP 连接请求。若内核在尝试建立连接过程中收到特定的网络响应(如 RST 包),便会向 JVM 返回一个错误码(在 Linux/Unix 系统中为 ECONNREFUSED,在 Windows 中为 WSAECONNREFUSED),JVM 再将其转换为 ConnectException 抛出。
因此,该异常反映的是网络层或传输层的问题,而非应用逻辑错误。
1.2 TCP 三次握手中的“拒绝”机制
理解此异常的关键在于掌握 TCP 协议的行为:
- 当客户端向目标主机的某端口发送 SYN(同步)包以发起连接时;
- 若目标主机的操作系统内核发现没有任何进程正在监听该端口;
- 内核将立即向客户端回送一个 RST(Reset)包,表示“此端口无服务,请勿重试”;
- 客户端操作系统收到 RST 后,向上层应用(即 Java 程序)报告“Connection refused”。
核心结论:Connection refused = 目标主机可达 + 目标端口无服务监听
这与 Connection timed out(连接超时)有本质区别:
- Timeout:SYN 包发出后未收到任何响应(可能因网络中断、防火墙丢包、主机宕机);
- Refused:SYN 包已送达,但对方明确告知“此处无服务”。
二、根本原因分类与排查指南
根据多年工程实践经验,导致 Connection refused 的原因可归纳为以下五大类。
2.1 服务进程未启动(最常见原因)
这是本地开发、测试环境中占比最高的原因。服务未运行,自然无法监听端口。
Windows 系统操作指南
在 Windows 操作系统中,MySQL、PostgreSQL、Redis 等数据库服务通常以“Windows 服务”的形式安装和管理。如果服务未启动,则对应的端口(如 MySQL 默认 3306)将不会被监听,从而导致 Connection refused 错误。
图形化界面操作步骤(推荐初学者使用)
打开“服务”管理控制台:
- 按下键盘上的
Win + R组合键,弹出“运行”对话框。 - 在输入框中键入
services.msc,然后按回车键或点击“确定”。 - 此时将打开“服务”窗口,其中列出了当前系统中所有已注册的服务。
- 按下键盘上的
查找目标数据库服务:
- 在服务列表中,滚动查找名称包含
MySQL的条目。 - 常见的服务名称包括:
MySQL80(MySQL 8.0 版本)MySQL57(MySQL 5.7 版本)MySQL(通用名称,多见于旧版安装)MariaDB(MariaDB 数据库)Redis(Redis 服务)
- 如果你不确定具体名称,可以右键点击任意服务 → “属性”,查看“路径到可执行文件”字段,确认是否为你安装的数据库程序。
- 在服务列表中,滚动查找名称包含
检查服务状态并启动:
- 查看“状态”列。如果该列为空白,说明服务当前未运行。
- 右键点击该服务名称,在弹出的上下文菜单中选择“启动”。
- 启动成功后,“状态”列将显示为“正在运行”。
- 如果启动失败(例如提示“错误 1067:进程意外终止”),则需进一步检查数据库的日志文件(通常位于
C:\ProgramData\MySQL\MySQL Server X.X\Data\目录下的.err文件)。
设置开机自动启动(可选):
- 为避免每次重启电脑后手动启动服务,可右键点击服务 → “属性”。
- 在“启动类型”下拉菜单中选择“自动”。
- 点击“应用”并“确定”。下次系统启动时,该服务将自动运行。
命令行方式(适用于脚本化或高级用户)
Windows 提供了强大的命令行工具来管理服务,无需依赖图形界面。
1.列出所有与 MySQL 相关的服务:
sc queryex type= service state= all | findstr /i "mysql"
sc(Service Control)是 Windows 内置的服务管理命令。- 此命令将输出所有服务名中包含“mysql”(不区分大小写)的服务及其状态。
2.启动指定服务:
net start MySQL80
- 将
MySQL80替换为你实际的服务名称。 - 成功启动后,命令行会显示“MySQL80 服务正在启动… MySQL80 服务已经启动成功。”
3.停止服务:
net stop MySQL80
4.查询服务详细信息:
sc qc MySQL80
此命令可查看服务的可执行文件路径、依赖关系、启动账户等关键信息,对排错非常有帮助。
macOS 系统操作指南
macOS 上的数据库服务管理方式取决于其安装途径。主流方式有两种:Homebrew(开发者首选)和 官方 .dmg 安装包。
A. 通过 Homebrew 安装的 MySQL(强烈推荐)
Homebrew 是 macOS 上最流行的包管理器,它能自动处理依赖、配置和后台服务管理。
检查 Homebrew 服务状态:打开“终端”(Terminal),输入以下命令:
brew services list
该命令会列出所有由 Homebrew 管理的后台服务。
输出示例:
Name Status User Plist
mysql stopped /Users/yourname/Library/LaunchAgents/homebrew.mxcl.mysql.plist
redis started yourname /Users/yourname/Library/LaunchAgents/homebrew.mxcl.redis.plist
Status 列显示 stopped 表示服务未运行。
启动 MySQL 服务:
# 启动服务,并设置为登录时自动启动(仅对当前用户) brew services start mysql # 或者,仅启动一次(不设为自动启动) brew services run mysql
start 命令会创建一个 launchd 配置文件(.plist),确保服务在用户登录时自动启动。
run 命令则只在当前终端会话中运行服务,关闭终端后服务也会停止。
停止服务:
brew services stop mysql
验证服务是否正常运行:
# 检查 MySQL 进程 ps aux | grep mysqld # 尝试连接数据库(默认 root 用户无密码,首次安装后建议运行 mysql_secure_installation) mysql -u root
查看日志(排错必备):Homebrew 安装的 MySQL 日志通常位于:
cat /opt/homebrew/var/mysql/$(hostname).err # 或 Intel Mac: cat /usr/local/var/mysql/$(hostname).err
B. 通过官方 .dmg 安装包安装的 MySQL
这种方式会将 MySQL 安装到 /usr/local/mysql/ 目录,并提供一个系统偏好设置面板。
图形化启动方式:
- 打开“系统设置”(System Settings)或旧版的“系统偏好设置”(System Preferences)。
- 在底部或侧边栏找到并点击 “MySQL” 图标。
- 在弹出的窗口中,你会看到一个大按钮:“Start MySQL Server”。
- 点击该按钮,状态会从 “MySQL Server is stopped.” 变为 “MySQL Server is running.”。
命令行启动/停止:官方安装包提供了便捷的脚本:
# 启动 MySQL sudo /usr/local/mysql/support-files/mysql.server start # 停止 MySQL sudo /usr/local/mysql/support-files/mysql.server stop # 重启 MySQL sudo /usr/local/mysql/support-files/mysql.server restart # 检查状态 sudo /usr/local/mysql/support-files/mysql.server status
- 这些命令本质上是调用了
mysqld_safe脚本来管理进程。 - 注意:需要
sudo权限,因为服务通常以_mysql用户身份运行。
添加 PATH(方便使用 mysql 命令):为了能在任意目录下直接使用 mysql 命令,需要将 MySQL 的 bin 目录加入环境变量。
编辑你的 shell 配置文件(如 ~/.zshrc 或 ~/.bash_profile):
echo 'export PATH="/usr/local/mysql/bin:$PATH"' >> ~/.zshrc source ~/.zshrc
之后即可直接在终端输入 mysql -u root -p 进行连接。
Linux 系统操作指南
Linux 发行版众多,但现代主流发行版(如 Ubuntu 16.04+、CentOS 7+、Debian 8+)均采用 systemd 作为初始化系统和服务管理器。旧版系统(如 CentOS 6)则使用 SysV init。
A. 使用 systemd(现代 Linux 发行版标准)
systemd 通过 systemctl 命令统一管理所有系统服务。
检查 MySQL 服务状态:不同发行版对 MySQL 服务的命名略有差异:
执行以下命令之一:
# Ubuntu/Debian sudo systemctl status mysql # CentOS/RHEL sudo systemctl status mysqld
Ubuntu/Debian 系:服务名为 mysql
CentOS/RHEL/Fedora 系:服务名为 mysqld
关键观察点:
Active: active (running):服务正在运行。Active: inactive (dead):服务已停止。- 如果提示
Unit ... not found,说明 MySQL 未安装。
启动、停止、重启服务:
# 启动服务 sudo systemctl start mysql # 或 mysqld # 停止服务 sudo systemctl stop mysql # 重启服务(修改配置后常用) sudo systemctl restart mysql # 重新加载配置(不中断服务) sudo systemctl reload mysql
设置开机自启:
# 启用开机自启 sudo systemctl enable mysql # 禁用开机自启 sudo systemctl disable mysql
enable 命令会在 /etc/systemd/system/multi-user.target.wants/ 目录下创建一个符号链接。
查看实时服务日志(排错神器):systemd 集成了日志系统 journald,可通过以下命令实时跟踪服务日志:
# 实时跟踪 MySQL 服务日志 sudo journalctl -u mysql -f # 查看最近 100 行日志 sudo journalctl -u mysql -n 100
这比直接查看 /var/log/mysql/error.log 更方便,因为它包含了 systemd 的元数据(如时间戳、进程ID)。
B. 使用 SysV init(旧版 Linux 系统)
虽然已逐渐被淘汰,但在一些遗留系统中仍会遇到。
检查服务状态:
sudo service mysql status # 或直接调用 init 脚本 sudo /etc/init.d/mysql status
管理服务:
# 启动 sudo service mysql start # 停止 sudo service mysql stop # 重启 sudo service mysql restart
设置开机自启:
# Ubuntu/Debian (使用 update-rc.d) sudo update-rc.d mysql defaults # CentOS 6 (使用 chkconfig) sudo chkconfig --level 35 mysql on
2.2 客户端连接配置错误
连接字符串(URL)中的 IP 地址、端口号或协议写错。
常见错误示例:
- JDBC URL:
jdbc:mysql://localhost:3360/testdb(端口应为3306); - 主机名拼写错误:
locahost、127.0..1; - 使用了错误的环境变量(如
DB_HOST=prod-db但在 dev 环境运行)。
排查重点:
- 检查
application.properties/application.yml; - 核对
.env文件或 Kubernetes ConfigMap; - 在 IDE 中打印完整的连接 URL(注意脱敏)。
2.3 服务绑定地址限制(Bind Address Issue)
服务虽已启动,但仅绑定到 127.0.0.1(loopback 接口),拒绝来自外部 IP 的连接。
典型表现:
- 本机可通过
127.0.0.1:3306连接 MySQL; - 但从同一局域网的另一台机器使用
192.168.1.100:3306连接失败,报Connection refused。
验证命令(在服务所在主机执行):
ss -tuln | grep :3306 # 或 netstat -tuln | grep :3306
输出示例:
tcp LISTEN 0 80 127.0.0.1:3306 0.0.0.0:*← 仅本机可连tcp LISTEN 0 80 0.0.0.0:3306 0.0.0.0:*← 所有接口可连
解决方案:
- MySQL:修改
my.cnf(位置通常为/etc/mysql/my.cnf或/etc/my.cnf),在[mysqld]部分添加或修改bind-address = 0.0.0.0,然后重启服务。 - Spring Boot:添加
server.address=0.0.0.0到配置文件。 - 自定义服务:确保
ServerSocket绑定到0.0.0.0或具体网卡 IP。
2.4 防火墙或安全组策略拦截
虽然服务在监听,但网络中间设备阻止了连接请求。
本地防火墙:
Windows:检查“Windows Defender 防火墙” -> “高级设置” -> “入站规则”,确保有允许目标端口(如 3306)的规则。
Linux (UFW):
sudo ufw status verbose sudo ufw allow 3306/tcp
Linux (firewalld):
sudo firewall-cmd --list-ports sudo firewall-cmd --permanent --add-port=3306/tcp sudo firewall-cmd --reload
云平台安全组(极易被忽视!):
- 阿里云/腾讯云/AWS/Azure:登录控制台,找到你的云服务器实例,进入“安全组”配置页面。
- 添加一条入站规则:协议类型
TCP,端口范围3306,授权对象0.0.0.0/0(测试用)或你的办公 IP。
2.5 容器化环境网络配置问题
在 Docker、Kubernetes 等容器平台中,网络命名空间隔离增加了复杂性。
Docker 常见问题:
- 未使用
-p参数映射端口:docker run mysql❌ vsdocker run -p 3306:3306 mysql✅; - 容器间通信使用了宿主机 IP 而非 Docker 自定义网络中的服务名。
Kubernetes 问题:
- Service 的
targetPort与 Pod 实际监听端口不一致; - Pod 未通过 Readiness Probe,Service 未将流量转发;
- NetworkPolicy 限制了跨命名空间通信。
排查命令:
docker ps # 查看运行容器 docker port <container_id> # 检查端口映射 kubectl get svc,pods -n <namespace> # 查看 K8s 服务状态
三、标准化排查流程(推荐顺序)
遵循 “由近及远、由内到外、先服务后网络” 的原则,逐步缩小问题范围。
步骤 1:确认目标服务是否真正运行并监听端口
操作位置:服务所在主机
# 检查进程 ps aux | grep <service_name> # 检查端口监听(关键!) ss -tuln | grep :<PORT> # 或 netstat -tuln | grep :<PORT>
- 若无输出 → 服务未启动或未监听该端口 → 启动服务。
- 若输出显示
127.0.0.1:<PORT>→ 仅本地可连 → 修改绑定地址。
步骤 2:核对客户端连接配置
操作位置:客户端代码/配置文件
- 检查 JDBC URL、HTTP endpoint、Redis 连接字符串等;
- 确保 IP、端口、协议(如
jdbc:mysql://)完全正确; - 注意环境变量覆盖问题(如
SPRING_DATASOURCE_URL)。
步骤 3:使用telnet或nc测试 TCP 连通性
操作位置:客户端主机
telnet <IP> <PORT> # 或 nc -vz <IP> <PORT>
- 成功:屏幕变黑或显示服务 banner(如 MySQL 版本信息);
- Connection refused:服务未监听(回到步骤 1);
- Timeout:网络不通或防火墙拦截(进入步骤 4)。
提示:Windows 可启用 Telnet 客户端功能,或使用 PowerShell 命令:
Test-NetConnection -ComputerName 127.0.0.1 -Port 3306
步骤 4:检查防火墙与云安全组
操作位置:服务所在主机 + 云控制台
- 临时关闭本地防火墙测试;
- 登录云平台控制台,检查实例关联的安全组规则;
- 确保入站规则允许
<PORT>/TCP来自你的 IP 或0.0.0.0/0(测试用)。
步骤 5:容器环境专项检查
操作位置:Docker Host / Kubernetes Cluster
- 确认容器运行状态:
docker ps/kubectl get pods; - 检查端口映射:
docker port <id>; - 在容器内部测试连接:
docker exec -it <container> telnet 127.0.0.1 <PORT>。
四、预防措施与工程最佳实践
4.1 自动化依赖管理
使用 docker-compose.yml 统一管理本地开发依赖(MySQL、Redis、Elasticsearch 等),避免手动启停遗漏。
version: '3'
services:
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root4.2 健康检查与启动探针
在应用启动时加入数据库连接探针,失败时提供友好提示:
@PostConstruct
public void checkDatabaseConnection() {
try (Connection conn = dataSource.getConnection()) {
// 成功
} catch (SQLException e) {
log.error("无法连接数据库,请检查服务是否启动及配置是否正确", e);
System.exit(1); // 或抛出自定义异常
}
}
4.3 配置分离与环境隔离
- 使用 Spring Profiles、Kubernetes ConfigMap/Secrets 管理不同环境配置;
- 避免硬编码连接信息,全部通过配置注入。
4.4 日志增强与可观测性
在捕获 ConnectException 时,记录完整的连接目标(脱敏后):
log.error("连接 {} 失败", maskUrl(url), e);集成 APM 工具(如 SkyWalking、Prometheus)监控服务依赖健康状态。
4.5 基础设施即代码(IaC)
使用 Terraform、Ansible 管理云资源与安全组,确保网络策略可版本化、可审计。
以上就是java.net.ConnectException: Connection refused报错的解决方法详解的详细内容,更多关于java.net.ConnectException报错解决的资料请关注脚本之家其它相关文章!
