端口被占用是系统进程所致,需用lsof/get-nettcpconnection/netstat查pid,再用kill/taskkill带子进程参数清理;live server、调试、远程扩展等须分场景改对应配置;防复发应禁用自动端口转发、用环境变量port、代码支持优雅关闭及监听ipv4/ipv6双栈。

端口被占用不是 VS Code 本身的问题,而是系统网络栈里已有进程绑定了你要用的端口——直接杀错进程或硬编码改端口,反而容易引发子进程残留、文件锁或跨项目冲突。
查谁在占着端口:用对命令,别被 DNS 卡住
别切出 VS Code 去找终端,直接在内置终端(Ctrl + `)里执行对应命令:
- macOS/Linux:
lsof -ni :5500(把5500换成你实际报错的端口号;-n跳过 DNS 解析,-i只筛网络连接) - Windows PowerShell:
Get-NetTCPConnection -LocalPort 5500(直接返回OwningProcess字段,就是 PID,最准) - Windows CMD:
netstat -ano | findstr :5500(输出中 PID 是十进制,需在任务管理器“详细信息”页开启“PID”列才能匹配)
如果 lsof 报 command not found,macOS 先运行 xcode-select --install 或 brew install lsof;Windows 上若 netstat 不可用,优先换 PowerShell 命令。
杀进程不能只 kill -9:Node 和 VS Code 进程树会偷偷续命
查到 PID 后,别立刻 kill -9 或 taskkill /f /pid。Live Server、调试器、甚至 Code Helper 进程常拉起 npm/yarn/子线程,硬杀主进程后,子进程可能继续占端口或锁文件:
- macOS/Linux:先
kill 1234(发 SIGTERM),等 2 秒无响应再kill -9 1234 - Windows:必须加
/t参数,taskkill /f /t /pid 1234,否则子进程大概率漏杀 - 更彻底清理 VS Code 自家进程:
killall -r "Code Helper|Code|Electron"(macOS/Linux)或taskkill /f /t /im Code.exe && taskkill /f /t /im CodeHelper.exe(Windows)
杀完立刻验证:lsof -i :5500 或 Get-NetTCPConnection -LocalPort 5500 应该无输出。有输出说明还有漏网之鱼。
改端口要对症下药:不同功能走不同配置项
光改 launch.json 的 port 字段,对 Live Server 无效;关掉所有调试会话再改,也未必解决 Codex 登录服务的 1455 端口冲突:
- Live Server 插件:在 VS Code 设置(
Cmd + ,或Ctrl + ,)里搜liveServer.settings.port,填个空闲端口如5501 - Node.js 调试:在项目根目录
.vscode/launch.json中确认port字段没硬编码成9229,改成9230或更高;也可设为"port": "${env:PORT}" - Codex 或 Remote-SSH:这类扩展内置服务端口无法通过
launch.json改,必须杀掉占用进程;Remote-SSH 可加配置"remote.SSH.defaultForwardedPorts": ["3001", "3002"]避免自动抢3000 - 前端脚手架(React/Vite):启动前设环境变量
PORT=3001 npm start,比改package.json快得多;Express/Koa 代码里别写死app.listen(3000),改成app.listen(process.env.PORT || 3000)
改完记得关掉已打开的调试会话或 Live Server 再重试,旧进程不会自动 reload 配置。
防复发的关键:别让端口写死在任何地方
真正省心的做法是让端口“动态可选”,而不是靠记忆或手动改配置:
- VS Code 设置里禁用自动端口转发:
remote.autoForwardPorts设为false,避免 Remote-SSH 自动抢3000 - 脚手架项目 scripts 里别写
react-scripts start --port 3000,留空让 CLI 自动找空闲端口,或统一用PORT环境变量控制 - Node 服务代码中监听逻辑必须带优雅关闭(
server.close())和信号监听(process.on('SIGINT', shutdown)),否则进程退出后套接字仍卡在TIME_WAIT
最容易被忽略的是 IPv6 和 IPv4 绑定差异:前一个服务监听 ::1:5500(IPv6 localhost),新进程试图绑 127.0.0.1:5500(IPv4),系统认为地址不同,但端口仍冲突——查占用时得同时看两类地址绑定。











