Mac 端口 3000 被占用:查找并结束占用进程
2026年10月13日更新
要在 Mac 上释放端口 3000,先运行 lsof -nP -iTCP:3000 -sTCP:LISTEN 看是哪个进程在监听,再用 kill <PID> 结束它。只有进程不理会普通信号时才用 kill -9。罪魁祸首通常是之前没关掉的开发服务器(Node、Vite、Next.js、Rails、Python)。
如果你不想敲命令,更想直接看一份监听端口列表,免费的 WTMemory 菜单栏 App会把端口和对应的进程一起列出来。文末会详细介绍;下面的终端方法在任何一台 Mac 上都适用。
“EADDRINUSE: address already in use :::3000” 是什么意思?
同一个 TCP 端口和地址同一时间只能有一个进程监听。当 Node 输出 Error: listen EADDRINUSE: address already in use :::3000,或者 Rails 提示 Address already in use - bind(2) for "127.0.0.1" port 3000 时,说明系统拒绝了绑定,因为已经有别的进程占着这个端口。你的新服务器本身没问题。你需要找到并停止旧的监听进程,或者换一个端口启动。
Mac 上怎么查看端口 3000 被谁占用?
macOS 自带 lsof(list open files,列出打开的文件),它也能列出网络套接字:
lsof -nP -iTCP:3000 -sTCP:LISTEN
典型输出:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 48213 you 23u IPv6 0x... 0t0 TCP *:3000 (LISTEN)
-iTCP:3000只显示端口 3000 上的 TCP 套接字。-sTCP:LISTEN只显示监听套接字,不显示连接到它的客户端。-n和-P跳过 DNS 解析和端口名查询,lsof 会快很多。
要结束的就是 PID 这一列。COMMAND 会被截断为九个字符,想看包括项目路径在内的完整命令行,运行 ps -p 48213 -o pid,ppid,etime,command。
一次列出这台 Mac 上所有正在监听的 TCP 端口:
lsof -nP -iTCP -sTCP:LISTEN
lsof 只显示你有权限查看的进程。如果端口被占用但 lsof 什么都没输出,说明监听进程属于其他用户或 root:加上 sudo 再运行一次。
怎么结束占用端口 3000 的进程?
kill 48213
再运行一次 lsof 命令。没有输出就说明端口已经空出来了。写成一行:
lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill
-t 只输出 PID,由 xargs 交给 kill。macOS 上的 BSD xargs 在没有输入时不会执行命令,所以端口本来就空闲时运行它也不会出问题。
务必保留 -sTCP:LISTEN 过滤条件。网上流传的 lsof -ti :3000 | xargs kill 还会匹配所有连接到端口 3000 的客户端,其中通常就有你打开着 localhost:3000 的浏览器标签页。不加过滤,你可能会把 Chrome 或 Safari 和服务器一起关掉。
kill 和 kill -9:该用哪个?
普通的 kill 发送 SIGTERM,礼貌地请进程退出。Node、Vite、Next.js、Rails 和大多数服务器都会捕获它,关闭套接字、写完日志并停止子进程。kill -9 发送 SIGKILL,由内核立即强制执行。进程没有机会做清理,因此:
- 子进程(worker、文件监听、打包工具)可能变成孤儿进程继续运行,并继续占着其他端口。
- 锁文件、PID 文件和临时文件会留下来,有些工具在你删掉它们之前拒绝启动。
- PostgreSQL、MySQL 等数据库下次启动时需要做崩溃恢复。请改用它们自己的工具来停止,比如
brew services stop postgresql@16。
先发 kill,等两三秒,用 lsof 检查,确实不行再升级到 kill -9。
为什么关了终端,服务器还在跑?
关闭终端窗口一般会挂断 shell 及其作业,但很多情况下进程能活下来:
- 按了 Ctrl+Z 而不是 Ctrl+C。Ctrl+Z 只是把服务器挂起;处于停止状态的进程仍然占着端口。运行
jobs,然后fg,再按 Ctrl+C。 - 孤儿子进程。
npm run dev会启动一个 shell,再由它启动node。如果父进程异常退出,子进程可能被launchd(PID 1)收养并继续提供服务。 - 编辑器内置终端和任务。VS Code、Cursor 和 JetBrains 系列 IDE 在窗口关闭或崩溃后,可能仍让内置终端和后台任务继续运行。
- tmux、screen、
nohup,或&加disown。它们本来就是为了在终端关闭后继续运行而设计的。 - 进程守护工具。
brew services(launchd)、pm2、nodemon 以及 Docker 的重启策略会立刻用新的 PID 把被结束的进程拉起来。
怎么按名称找出残留的开发服务器?
当残留的服务器有好几个时,按名称列出它们,同时显示父进程 PID 和运行时长:
ps -axo pid,ppid,etime,command | grep -E 'node|vite|next|webpack|rails|python' | grep -v grep
PPID 为 1 说明进程成了孤儿,被 launchd 收养。ETIME 很长(好几天,或者没开终端却跑了好几个小时)也是一个信号。pgrep -fl vite 给出的列表更简短。你可以用 pkill -f "next dev" 按模式结束进程,但请先用 pgrep -fl "next dev" 看看会匹配到什么,因为 -f 会在完整命令行的任意位置匹配。
如果是 Docker 占着端口怎么办?
如果 lsof 显示的是 Docker 进程(例如 com.docker.backend),说明是某个容器发布了这个端口。不要结束 Docker 进程,否则所有容器都会停掉。找到那个容器并停止它:
docker ps --filter "publish=3000"
docker stop <container>
Mac 上常见的开发端口
| 端口 | 通常的占用者 |
|---|---|
| 3000 | Next.js、Create React App、Nuxt、Rails、很多 Express 应用 |
| 4200 | Angular CLI |
| 5000, 7000 | AirPlay 接收器(ControlCenter)、Flask 默认端口 |
| 5173, 4173 | Vite 开发服务器、Vite 预览 |
| 8000 | Django、python3 -m http.server |
| 8080 | Tomcat、Spring Boot、各种代理 |
| 8888 | Jupyter |
| 5432, 3306, 6379, 27017 | PostgreSQL、MySQL、Redis、MongoDB |
| 11434 | Ollama |
同样的 lsof 命令对这些端口都适用:把 3000 换成对应的端口号即可。
macOS 上为什么端口 5000 或 7000 被占用?
从 macOS Monterey 开始,AirPlay 接收器会监听 5000 和 7000 端口,lsof 显示的占用者是 ControlCenter。这就是为什么在一台什么都没运行的 Mac 上,新建的 Flask 应用也会报 “Address already in use”。不要结束 ControlCenter,macOS 会重新启动它。你可以:
- 在 系统设置 > 通用 > 隔空投送与接力 中关闭 AirPlay 接收器(Monterey 上是 系统偏好设置 > 共享),或者
- 让应用跑在别的端口上,比如
flask run --port 5001。
以后怎么避免端口冲突?
- 用 Ctrl+C 而不是 Ctrl+Z 停止服务器,关闭终端前先看一眼
jobs。 - 需要同时跑两个项目时换个端口:
PORT=3001 npm start、next dev -p 3001或vite --port 5174。 - Vite 会自动换到下一个空闲端口。如果你宁愿让它直接报错、好发现残留的服务器,就加上
--strictPort。
在菜单栏里查看端口被谁占用
WTMemory 是一款原生 macOS 菜单栏 App,支持 macOS 12 及以上版本,兼容 Apple 芯片和 Intel 机型。在菜单中选择 Find What's Using a Port(查找端口占用),即可看到所有 TCP 监听端点及其背后的进程;或者打开 Running Apps(运行中的 App),查看每个开发进程的 PID、可执行文件位置、内存和 CPU 占用。查看功能免费。
结束进程属于 Pro 功能,执行前你会先核对并确认。停止一个监听进程会结束整个进程,而不只是释放一个端口;WTMemory 不会把进程标记为“已废弃”或“可以安全结束”,由你自己决定。用锁定按钮保护的应用永远不会被退出。Pro 一次性付费 $9 USD,最多可用于三台 Mac,并提供七天试用。
常见问题
怎样用一条命令结束占用端口 3000 的进程?
运行 lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill。-sTCP:LISTEN 这个过滤条件很关键:少了它,lsof 还会返回连接到端口 3000 的客户端(比如你的浏览器),它们也会被一起结束。
kill -9 不好吗?
它是最后手段。SIGKILL 会立即结束进程,进程来不及写完数据、删除锁文件或停止子进程。先用普通的 kill,等几秒再说。
为什么进程结束后又自己起来了?
有东西在重启它:通过 launchd 运行的 Homebrew 服务、pm2、nodemon、文件监听工具,或者设置了重启策略的 Docker 容器。请改用对应工具来停止,比如 brew services stop 或 docker stop。
查看端口占用需要 sudo 吗?
只有进程属于其他用户或 root 时才需要。如果 lsof 什么都没显示但端口仍被占用,就加上 sudo 再运行同样的命令。
Mac 上什么都没运行,为什么端口 5000 被占用?
从 macOS Monterey 开始,AirPlay 接收器会通过 ControlCenter 进程监听 5000 和 7000 端口。在系统设置中关闭 AirPlay 接收器,或者让你的应用换个端口运行。