TimeFence: persistent focus timer HUD — buy direct, lifetime license.
Engineering PortDetective

Fix EADDRINUSE on Windows

Published April 9, 2026 9 min read

If you build on Windows long enough, you eventually memorize the shape of the failure before you even read it:

Error: listen EADDRINUSE: address already in use :::3000

It usually shows up when you are doing something routine:

  • starting a Vite dev server
  • running a React or Next.js app locally
  • relaunching an Express or Fastify API
  • bringing a Dockerized service back up after a crash

Most tutorials reduce the fix to “find the PID and kill it.” That works, but it skips the useful part: what the error actually means, why Windows returns it, and how to tell the difference between a stale dev server and something you should leave alone.

This guide walks through the full manual fix, starting at the OS networking layer and ending with the exact PowerShell commands most Windows developers use in practice.

If you want the broader “find the owner, inspect the process, then decide what to kill” workflow, How to Find and Fix Port Conflicts on Windows is the companion piece.

What EADDRINUSE actually means

EADDRINUSE is the application-level way of saying a bind operation failed because the address is already in use.

At the Windows networking layer, your process is asking Winsock to bind a socket to a local tuple that usually looks like this:

  • IP address: 0.0.0.0, 127.0.0.1, or ::
  • port: 3000, 5173, 8080, 5432, and so on
  • protocol: usually TCP for local dev servers

Only one listener can normally own a given local address and port combination at a time. If another process is already listening there, the bind request fails. Node.js, Bun, Deno, Python, Go, and other runtimes all eventually surface that same underlying condition.

In plain English:

  • your app asked Windows for a port
  • Windows checked the socket table
  • something else already had that claim
  • the runtime bubbled it up as EADDRINUSE

That is why this error is not really a “Node problem.” It is a local process ownership problem.

Why this happens so often on Windows dev machines

Modern local environments are crowded.

A typical workstation may have all of these competing for ports at the same time:

  • a frontend dev server on 3000 or 5173
  • an API on 8080 or 4000
  • PostgreSQL on 5432
  • Redis on 6379
  • Docker proxy processes
  • WSL-forwarded services
  • background watchers that never shut down cleanly

The most common failure mode is simple: a process from a previous run is still listening.

The second most common failure mode is more subtle: the process exited, but you are looking at the wrong state. For example, an established TCP connection in TIME_WAIT is not the same thing as a live listener in LISTENING. If you do not read the state column, you can chase the wrong explanation.

The manual PowerShell fix

If your goal is to fix EADDRINUSE on Windows right now, this is the workflow most developers end up using.

Step 1: Find the process bound to the port

Open PowerShell and search for the port:

netstat -ano | findstr :3000

Breakdown:

  • netstat shows active connections and listening ports
  • -a includes listeners
  • -n shows numeric addresses and ports
  • -o includes the owning PID
  • findstr :3000 filters the output to the port you care about

Example output:

TCP    0.0.0.0:3000      0.0.0.0:0      LISTENING      14532
TCP    [::]:3000         [::]:0         LISTENING      14532

What matters is the final column: 14532.

Step 2: Confirm what that PID belongs to

Before killing anything, confirm the process:

tasklist /FI "PID eq 14532"

Or, if you want a PowerShell-native view:

Get-Process -Id 14532

This is the step people skip when they are in a hurry. That is how you accidentally kill the wrong node.exe, python.exe, or java.exe.

Step 3: Terminate it

If you are sure it is safe to stop:

taskkill /PID 14532 /F

That force-terminates the process and should free the port immediately.

The short version

If you already know the port and just want the three-command sequence:

netstat -ano | findstr :3000
tasklist /FI "PID eq 14532"
taskkill /PID 14532 /F

That is the canonical manual answer to “fix EADDRINUSE windows.”

How to read the netstat output correctly

The dangerous part of the manual workflow is not the command. It is sloppy interpretation.

LISTENING means a process currently owns the port

If you see:

TCP    0.0.0.0:3000      0.0.0.0:0      LISTENING      14532

that is a straightforward port conflict. Something is actively bound there.

TIME_WAIT is not the same problem

If you see:

TCP    127.0.0.1:3000    127.0.0.1:52311    TIME_WAIT    0

that does not mean a process is still listening on the port. TIME_WAIT is part of TCP connection teardown. It often appears after an app shuts down normally.

For local dev troubleshooting, the practical rule is simple:

  • LISTENING usually explains EADDRINUSE
  • TIME_WAIT usually does not

Common Windows scenarios behind EADDRINUSE

Vite or React is still running in another terminal

This is the classic case. You closed the editor window, forgot the terminal was still open, or the watcher got detached.

Your server crashed but the child process did not

This happens with bundlers, proxies, container helpers, and background task runners. The parent process dies, but the child still owns the port.

WSL2 or Docker forwarded a port onto the Windows host

Sometimes the process you care about is not the app you launched directly. It is the bridge process exposing the port on behalf of a VM or container.

You are colliding with a real service

Not every listener is disposable. Ports like 80, 443, 5432, and 6379 may belong to IIS, a local database, or infrastructure you actually need. Treat those more carefully than a stale frontend server.

A safer native alternative: PowerShell objects

netstat is universal, but it is still raw text. On newer Windows systems, this is often easier to inspect:

Get-NetTCPConnection -LocalPort 3000 |
  Select-Object LocalAddress, LocalPort, State, OwningProcess

Then resolve the process:

Get-Process -Id (
  Get-NetTCPConnection -LocalPort 3000
).OwningProcess

This gives you structured objects instead of column parsing. It is a cleaner workflow, but it still leaves you doing manual correlation and manual termination.

Why the manual fix gets old fast

The manual fix is fine once.

It is miserable when it becomes part of your weekly loop.

If you are bouncing between Vite, React, Node, Docker, databases, and multiple repos, the cost is not just the three commands. It is the interruption:

  • switch out of the editor
  • remember the port
  • run lookup commands
  • translate the PID into a process
  • kill it
  • rerun the app

That is a lot of ceremony for a problem that is usually obvious: an old dev server is still hanging around.

When you should not blindly run taskkill /F

There are cases where the brute-force fix is the wrong one:

  • the listener belongs to PostgreSQL and you still need the database
  • the port is held by a Windows service that will just restart
  • the PID belongs to a process you did not intend to stop
  • the PID changed between lookup and termination

That last case is the subtle one. Windows can recycle PIDs. If you look up a PID, get distracted, then kill it later, you are trusting that the number still points to the same process. That assumption is shakier than most tutorials admit.

If you want that deeper story, read The PID race behind Windows process kills.

When EADDRINUSE keeps interrupting your dev loop, a focused port utility with safer kill checks is available in

Get PortDetective on Microsoft Store

A better workflow for repeated EADDRINUSE conflicts

Manual commands are great for understanding the system. They are not a great long-term user experience.

What developers actually want is:

  • instant visibility into listeners
  • filtering by port without parsing text
  • enough process context to know what they are killing
  • a faster path back to shipping code

That is the gap PortDetective is built to close.

Instead of waiting for an EADDRINUSE failure, copying a PID out of netstat, and force-killing a process from memory, PortDetective can sit in the background as a lightweight watchdog for the exact conflicts developers hit over and over on Windows.

For teams juggling Vite, React, Node, local APIs, and databases all day, that matters. The manual process is educational. It is also repetitive. PortDetective turns that routine into a one-click recovery path instead of a fresh round of terminal archaeology every time a stale server grabs 3000 or 5173.

For teams juggling Vite, React, Node, and local databases, turning terminal archaeology into a one-click recovery path starts with

Get PortDetective on Microsoft Store

// release_radar

Unlock a $5 Credit Toward the Automata Ecosystem.

We build native, local-first tools for professionals who refuse SaaS fatigue. Drop your email to instantly receive a $5 credit code valid for the complete Windows Productivity Bundle, plus early access to future zero-telemetry releases.