Go报connection refused本质是目标IP:port无进程监听或被防火墙拒绝,操作系统内核回RST包;应先用lsof/netstat确认服务端LISTEN状态,检查绑定地址是否为0.0.0.0而非127.0.0.1,并用errors.Is(err, syscall.ECONNREFUSED)精准判断。
go报connection refused基本不是代码写错了,而是目标服务压根没在监听那个ip:port——操作系统内核直接回了rst包,go只是原样透出错误。
先验证目标端口是否真在LISTEN状态
别改Go代码,先确认服务端活着且绑对了地址:
- Linux/macOS执行
lsof -i :3306或netstat -tuln | grep :3306;有输出且状态是LISTEN才说明进程在跑 - Windows执行
netstat -ano | findstr :3306,重点看“本地地址”列:必须是0.0.0.0:3306或*:3306,若只显示127.0.0.1:3306,容器或远程调用必拒 - MySQL默认
bind-address = 127.0.0.1,要改my.cnf为0.0.0.0并重启;Go HTTP服务若写http.ListenAndServe("localhost:8080", nil),也得改成:8080
排查代理、hosts、DNS无声劫持
这些配置会把你的请求悄悄转向错误地址,表面看是连接拒绝,实则是被“拐走”了:
- 检查Git代理残留:
git config --get http.proxy,若输出http://127.0.0.1:7890这类,Go的http.Client默认继承,结果连本地代理端口都失败 - 打开
/etc/hosts(Linux/macOS)或C:\Windows\System32\drivers\etc\hosts(Windows),搜索目标域名(如goproxy.cn),临时注释掉所有相关行再试 -
go env GOPROXY若为https://proxy.golang.org,direct,国内大概率直连失败;执行go env -w GOPROXY=https://goproxy.cn,direct可绕过
Go代码里如何可靠判断和响应
字符串匹配"connection refused"不可靠,不同系统locale下可能乱码或中文;必须用标准错误判定:
- 用
errors.Is(err, syscall.ECONNREFUSED)(Go 1.13+),它自动展开嵌套错误(如*url.Error→*net.OpError→底层syscall错误) -
net.Error.Temporary()对ECONNREFUSED返回false——这是Go标准库明确设计,说明它不是临时故障,重试价值极低 - 重试最多1–2次,并记录具体目标,例如
"failed to dial mysql on 127.0.0.1:3306 (service not running?)",比泛泛而谈“连接失败”有用得多
Docker和容器场景下的特殊坑
容器里localhost指自己,不是宿主机,这点极易踩空:
- Go应用容器连宿主机MySQL,不能用
localhost:3306,Mac/Windows用host.docker.internal:3306,Linux用172.17.0.1:3306 - 容器间通信(如Go服务连
otel-collector),确保Collector的配置中receivers.otlp.protocols.grpc.endpoint设为0.0.0.0:4317,而非127.0.0.1:4317 - Docker Compose的
depends_on只保启动顺序,不保服务就绪;Go客户端需主动加重试逻辑,等otel-collector:4317真正可连再初始化exporter
最常被忽略的是:这个错误从不发生在DNS解析阶段,也不代表网络不通——它只说明TCP握手时对方明确说了“没人”,所以查端口监听状态永远是第一动作,其他都是干扰项。

















