Skip to content
DevOps2026-09-084 分钟阅读

ECONNREFUSED 连接被拒绝怎么排查?5 种原因一次讲清(含 Docker 场景)

现象:各种语言,同一个错

# Node.js
Error: connect ECONNREFUSED 127.0.0.1:3306
    at TCPConnectWrap.afterConnect (node:net:1607:16)

# curl
curl: (7) Failed to connect to 127.0.0.1 port 6379: Connection refused

# Java
java.net.ConnectException: Connection refused (Connection refused)

一行结论:网络能到达那台机器,但你连的那个端口上没有任何进程在监听。操作系统直接回了个 RST(reset)拒绝连接——注意它和「超时」的区别:超时(ETIMEDOUT)是包根本到不了或被丢,拒绝(REFUSED)是到了但没人应答,这个区分直接决定排查方向。

| 报错 | 含义 | 大方向 | |---|---|---| | ECONNREFUSED | 到了,端口没人听 | 查服务/端口 | | ETIMEDOUT | 包没到或被丢 | 查网络/防火墙 |

五种原因,按概率排序

1. 服务压根没起来(最常见)

systemctl status mysql        # Linux 服务
docker ps                     # 容器在跑吗?重启过吗?
brew services list            # macOS

容器退出后自动重启失败是高频场景:docker ps -a 里看 STATUS 是 Restarting (1) 5 seconds ago 还是 Up。前者说明容器在崩溃循环,端口自然连不上。

2. 端口记错了

各服务默认端口速查:

| 服务 | 默认端口 | |---|---| | MySQL | 3306 | | PostgreSQL | 5432 | | Redis | 6379 | | MongoDB | 27017 | | Elasticsearch | 9200 | | RabbitMQ | 5672 |

两个易错点:Redis 配置里写的是 port 6379,但你用 --port 参数覆盖过;MySQL 改过 my.cnfport=以实际监听为准,别以记忆为准

ss -tlnp | grep -E '3306|6379'    # Linux
lsof -nP -iTCP:3306 -sTCP:LISTEN  # macOS

3. 服务只监听了 127.0.0.1,你从别的机器连

ss -tlnp | grep 5432
# LISTEN 127.0.0.1:5432   ← 只接受本机连接
# LISTEN 0.0.0.0:5432     ← 接受任意来源
# LISTEN [::]:5432        ← IPv6 任意来源

如果是 127.0.0.1:端口,远程连接一律拒绝。修法按服务改监听地址:MySQL 注释掉 bind-address=127.0.0.1、PostgreSQL 改 listen_addresses = '*'、Redis 改 bind 0.0.0.0(同时务必配 requirepass,Redis 裸奔公网是勒索重灾区)。

4. Docker 场景:localhost 在容器里不是宿主机

容器内连宿主机上的服务,127.0.0.1 指的是容器自己,不是宿主机:

# 容器里的应用连数据库——两种正确姿势
# 姿势一:都在 docker network 里,用服务名(推荐)
spring.datasource.url: jdbc:mysql://interview-mysql:3306/mydb

# 姿势二:容器连宿主机上的服务
# macOS/Windows Docker Desktop 用专属域名:
jdbc:mysql://host.docker.internal:3306/mydb
# Linux 宿主机(Docker 20.10+)加 extra_hosts:
services:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"

反过来,宿主机连容器:必须依赖 docker run -p 127.0.0.1:3306:3306 这样的端口映射,没映射 -p,宿主机上 curl localhost:3306 必然 ECONNREFUSED。

5. 防火墙主动 REJECT

iptables 的 REJECT 规则会回 RST,表现和「没人监听」一模一样(DROP 才表现为超时):

sudo iptables -L -n | grep -i reject

云服务器还有一层安全组——阿里云/腾讯云控制台里的安全组规则没放行端口,表现也可能是拒绝或超时,且服务器内部 ss 看一切正常。这是「本地正常、上云就连不上」的经典原因。

排查路线(从下往上三层)

# 第一层:端口上有人听吗?
ss -tlnp | grep <端口>

# 第二层:本机能连通吗?
nc -zv 127.0.0.1 <端口>

# 第三层:目标机器/容器网络里能连通吗?
docker exec -it <容器> sh -c 'nc -zv <目标地址> <端口>'

第一层没人听 → 原因 1/2;本机能通远程不能 → 原因 3/5;容器里连不上 → 原因 4。三层走完,问题基本定位。

顺手区分:ECONNREFUSED vs EADDRINUSE

一个端口的两端视角:连接别人时被拒是 ECONNREFUSED(对面没人听);自己监听时被占是 EADDRINUSE(这端口已被别人占了)。后者的排查看这篇:端口被占用怎么办?EADDRINUSE 报错排查

排查清单

  1. docker ps / systemctl status — 服务活着吗?(含崩溃循环检查)
  2. ss -tlnp | grep <端口> — 实际监听端口和地址是什么?
  3. 监听地址是 127.0.0.1 还是 0.0.0.0?远程连接必须后者
  4. Docker 里连宿主机服务:用 host.docker.internal,不是 localhost
  5. 云服务器查安全组规则,服务器内查 iptables REJECT
  6. 分清 REFUSED(到了没人听)和 TIMEOUT(到不了),方向完全不同

本文由 ToolVault 工具匣 提供。相关工具:Dockerfile 生成器CIDR 子网计算API 在线测试。相关阅读:端口被占用 EADDRINUSE 排查。访问 首页 查看更多开发者工具。


广告