Error: listen EADDRINUSE: address already in use :::3000 —— 开发时最常见的报错之一。端口被占了,快速找到谁在用、怎么处理,是每个后端开发的基本功。
三个操作系统的排查命令
macOS
# 查谁占用了 3000 端口
lsof -i :3000
# 输出示例:
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# node 12345 user 23u IPv6 0x... 0t0 TCP *:3000 (LISTEN)
# 只输出 PID(方便传给 kill)
lsof -t -i :3000
# 一行杀掉
kill -9 $(lsof -t -i :3000)
# 查所有监听中的端口
lsof -i -P -n | grep LISTEN
Linux
# ss(现代工具,比 netstat 快)
ss -tlnp | grep :3000
# t=TCP, l=listening, n=不解析域名, p=显示进程
# 输出示例:
# LISTEN 0 128 *:3000 *:* users:(("node",pid=12345,fd=23))
# 查所有监听端口
ss -tlnp
# 老工具 netstat(部分系统需要安装 net-tools)
netstat -tlnp | grep :3000
# 一行杀掉
fuser -k 3000/tcp
Windows(PowerShell / CMD)
:: 查端口占用,找 PID
netstat -ano | findstr :3000
:: 输出示例:
:: TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345
:: 查 PID 对应的进程名
tasklist | findstr "12345"
:: 杀掉进程
taskkill /PID 12345 /F
:: PowerShell 一行搞定
Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess
端口号的三个区间
0 1023 49151 65535
|--------|---------|---------|
知名端口 注册端口 动态端口
(需root) (应用层) (临时连接)
开发项目惯例:选 3000-9999 范围,不会和系统服务冲突,也不会被操作系统随机分配给临时连接。
开发常用端口速查
Web 服务
| 端口 | 服务 | 备注 |
|---|---|---|
| 80 | HTTP | 需 root |
| 443 | HTTPS | 需 root |
| 3000 | Node.js 开发惯例 | React/Next.js 默认 |
| 4321 | Astro dev | — |
| 5173 | Vite dev | — |
| 8080 | HTTP 备用 / Tomcat | 不需要 root |
| 8443 | HTTPS 备用 | — |
数据库
| 端口 | 服务 |
|---|---|
| 3306 | MySQL / MariaDB |
| 5432 | PostgreSQL |
| 27017 | MongoDB |
| 6379 | Redis |
| 9200 | Elasticsearch HTTP |
| 9300 | Elasticsearch 节点间通信 |
| 5984 | CouchDB |
消息队列 / 流
| 端口 | 服务 |
|---|---|
| 5672 | RabbitMQ AMQP |
| 15672 | RabbitMQ 管理界面 |
| 9092 | Kafka |
| 2181 | ZooKeeper |
基础设施
| 端口 | 服务 |
|---|---|
| 22 | SSH |
| 21 | FTP 控制 |
| 20 | FTP 数据 |
| 25 | SMTP |
| 53 | DNS |
| 123 | NTP |
| 3389 | Windows 远程桌面(RDP) |
容器 / 编排
| 端口 | 服务 |
|---|---|
| 2375 | Docker daemon(HTTP,不安全) |
| 2376 | Docker daemon(HTTPS) |
| 6443 | Kubernetes API Server |
| 10250 | kubelet API |
| 2379-2380 | etcd |
常见冲突场景
场景一:本机多个项目同时开发
项目 A 默认 3000,项目 B 也默认 3000。
# 方法一:启动时指定不同端口
PORT=3001 npm start # 项目 B 改用 3001
# 方法二:.env 文件写死各项目端口
# 项目A: PORT=3000
# 项目B: PORT=3001
场景二:Docker 容器宿主机冲突
# 查宿主机 8080 是谁在用
lsof -i :8080
# 改 docker run 的端口映射
docker run -p 8081:80 myapp # 用 8081 替代 8080
场景三:服务 crash 后快速重启报错
# 等 TIME_WAIT 超时(1-2 分钟)
# 或者直接找残留进程
lsof -i :3000
kill -9 <PID>
# Linux 加速:修改内核参数(重启后生效)
echo "net.ipv4.tcp_tw_reuse=1" >> /etc/sysctl.conf
防火墙端口管理
开放端口到外网前确认服务是否需要公网访问:
# Linux iptables 开放 8080
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# firewalld(RHEL/CentOS 7+)
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload
# ufw(Ubuntu)
ufw allow 8080/tcp
数据库(MySQL 3306、Redis 6379)不应该直接开放公网端口,通过 VPN 或 SSH 隧道访问:
# SSH 隧道把远程 3306 映射到本地 3307
ssh -L 3307:127.0.0.1:3306 user@remote-host