/인프라/Fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)
Infrastructureaddress already in useEADDRINUSE

Fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)

When bind: address already in use or EADDRINUSE leaves you stuck, this guide walks through finding the occupying process with lsof and netstat, terminating it safely, and stopping TIME_WAIT and duplicate startups with copy-paste commands fo

Fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)

Completely fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)

A red line just appeared in the console — this error means only one thing

If you're trying to start a server and the console dumps bind: address already in use or EADDRINUSE, the message is really saying just one thing.

A single port can be occupied by only one process at a time.

In other words: "someone is already holding the port you want (e.g. 8080)." The culprit is one of three:

  1. Yourself — a server you started a moment ago is still alive (hot-reload orphan processes are a classic)
  2. Another process — a completely unrelated app already claimed the same port
  3. A container — Docker has mapped and is holding the host port

This post is structured so you can finish by following diagnose → terminate → prevent recurrence. Copy-paste from top to bottom.

Step 1: Diagnose — lookup table by error message pattern

First, look at the exact message in the console. The wording differs by environment, but the essence is the same.

EnvironmentActual console outputLikely culpritFirst command to run
Node.jsError: listen EADDRINUSE: address already in use :::8080Usually the app itself (duplicate start / nodemon orphan)lsof -i :8080
PythonOSError: [Errno 98] Address already in useleftover process from a uvicorn/flask restartlsof -i :8000
nginxbind() to 0.0.0.0:80 failed (98: Address already in use)another web server / previous nginx instancess -ltnp 'sport = :80'
DockerBind for 0.0.0.0:8080 failed: port is already allocatedanother container holding the host portdocker ps

Once you've found your case in the table, use the first command to identify who is holding the port.

Step 2: Terminate — find the occupying process and kill it safely

All examples below use port 8080. Replace it with your own port before running.

Linux / macOS

Bash
# 1) 포트를 점유한 프로세스(PID)와 이름 확인
lsof -i :8080

# 2) 대체 명령 — ss는 lsof보다 가볍고 리눅스 기본 탑재
ss -ltnp 'sport = :8080'

# 3) fuser로 한 번에 확인
fuser 8080/tcp

Once you've identified the PID column in the lsof -i :8080 output, terminate it.

Bash
# 먼저 우아하게 (권장)
kill -15 <PID>

# 10초 기다려도 안 죽으면 강제 종료
kill -9 <PID>

# fuser로 한 방에 종료하고 싶다면
fuser -k 8080/tcp

Windows (PowerShell / CMD)

POWERSHELL
# 포트를 점유한 PID 찾기 (맨 끝 숫자가 PID)
netstat -ano | findstr :8080

# 해당 PID 강제 종료
taskkill /PID <PID> /F

kill -15 vs kill -9: order matters

  • kill -15 (SIGTERM): a "clean up and leave" signal. The app closes open files, tears down DB connections, then exits. Always use this first.
  • kill -9 (SIGKILL): kills the process immediately. Blindly using -9 can lose in-flight data or leave lock files and temporary sockets behind, making things worse. Use it only as a last resort when SIGTERM does not work.

Step 3: Prevent recurrence — prescriptions by root cause

Killed it, started again, and the same error came back? Then you need to pull the cause out by the roots.

1) Leftover TIME_WAIT sockets → SO_REUSEADDR

If you stop a server and start it again immediately, the socket you just closed stays in TIME_WAIT for tens of seconds and holds the port, causing EADDRINUSE. Enabling SO_REUSEADDR lets you reuse a port in that state.

Node.jsnet/http servers have SO_REUSEADDR on by default, but it's still a good idea to handle the error explicitly and fail fast.

JavaScript
const server = http.createServer(app);
server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error('포트 8080 사용 중. 점유 프로세스를 먼저 종료하세요.');
    process.exit(1);
  }
});
server.listen(8080);

Python

Python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # TIME_WAIT 포트 재사용
s.bind(('0.0.0.0', 8000))
s.listen()

2) Hot-reload orphan processes

If nodemon or uvicorn --reload exits abnormally, child workers lose their parent and linger as orphan processes still holding the port. They often survive even after you close the terminal, so hunting them down with lsof from Step 2 is the reliable fix.

3) Duplicate starts from systemd or pm2

If a process manager is set to auto-restart, it will collide with a server you started by hand.

Bash
# pm2가 같은 앱을 이미 띄워두지 않았는지 확인
pm2 list

# systemd 서비스가 포트를 잡고 있는지
systemctl status myapp.service

Before a manual test, stop the manager first with pm2 stop <name> or systemctl stop.

4) Docker Compose port mapping conflicts

Bind for 0.0.0.0:8080 failed: port is already allocated means the host port is already taken.

Bash
# 8080을 잡고 있는 컨테이너 찾기
docker ps

If you find a container whose PORTS column shows 0.0.0.0:8080->..., change only the host port in compose to a free value.

YAML
services:
  web:
    ports:
      - "8081:80"   # 왼쪽(호스트)만 변경, 오른쪽(컨테이너)은 그대로

Practical tip: Locally, the most common causes are "the previous server never died" and "forgot to bring compose down." If you use containers, make docker compose down a habit at the end of a session. If hot-reload often leaves orphans, register lsof -i :<port> as a shell alias. Diagnosis drops to 30 seconds.

Conclusion — 3-step summary and copy-paste checklist

  1. Diagnose: use the exact error text to tell whether the culprit is the app, another process, or a container
  2. Terminate: find the PID with lsof -i :<port> (or netstat -ano), then kill -15kill -9 if that fails
  3. Prevent recurrence: SO_REUSEADDR, clean up orphans, and check process-manager / compose ports
Bash
# 복붙용 한 줄 진단 (Linux/macOS)
lsof -i :8080 || ss -ltnp 'sport = :8080'

FAQ

Q. Can I just switch to a different port number? A. As a temporary workaround, yes. But changing the port does not make the zombie/orphan process go away — you're still leaking resources. The real fix is to terminate the occupying process.

Q. Rebooting fixed it for me. Is that the right answer? A. A reboot resets every process and TIME_WAIT socket, so of course it clears. But the cause is still there, so it will come back. Use steps 2–3 in this post to remove the root cause.

Q. Bind fails with Permission denied. Is that a port conflict too? A. No. Ports below 1024 (80, 443, etc.) require root privileges. Run with sudo, use a port 1024 or above like 8080, or grant the capability with setcap. That's a different problem from address already in use.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.