Recently I ran into a puzzling issue:
I started an Express app, the console said it was "Running on port 3000", but when I tried to visit http://127.0.0.1:3000, the browser couldn’t connect.
Here’s the step-by-step diagnosis process.
Diagnosis
1. Checked Proxy Settings
I do use proxy software, but system proxy rules normally ignore local addresses like 127.0.0.1.
→ Not the cause.
2. Checked Port Conflicts & IP
No other process was using port 3000, and this wasn’t a DNS issue.netstat -ano | findstr 3000 showed nothing blocking it.
→ Still no luck.
3. Checked the Code
To rule out my app logic, I created a fresh, empty Express project. Same issue — server “runs,” but page is inaccessible.
→ Not a code problem.
4. Checked if Node Can Run a Pure HTTP Server
I tried spinning up a simple Node HTTP server without Express:
node -e "const s=require('http').createServer((req,res)=>res.end('ok')).listen(3000,'127.0.0.1',()=>{console.log('addr',s.address(),'pid',process.pid)});"
Result:
> node -e "const s=require('http').createServer((req,res)=>res.end('ok')).listen(3000,'127.0.0.1',()=>{console.log('addr',s.address(),'pid',process.pid)});"
node:events:496
throw er; // Unhandled 'error' event
^
Error: listen EACCES: permission denied 127.0.0.1:3000
at Server.setupListenHandle [as _listen2] (node:net:1855:21)
at listenInCluster (node:net:1920:12)
at doListen (node:net:2075:7)
at process.processTicksAndRejections (node:internal/process/task_queues:83:21)
Emitted 'error' event on Server instance at:
at emitErrorNT (node:net:1899:8)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'EACCES',
errno: -4092,
syscall: 'listen',
address: '127.0.0.1',
port: 3000
}
Node.js v20.11.1
So — permission denied when binding to port 3000.
5. Tried Admin Privileges
I ran PowerShell as Administrator, restarted the server…
Same error.
That means this isn’t a simple “need admin rights” issue.
6. Found the Real Cause — Windows Reserved Ports
On Windows, some ports are excluded/reserved for system use (often by Hyper-V, WSL/Docker, VPN, or ICS).
When a port is in this range, Node.js gets an EACCES error even if it’s not privileged (<1024).
To see the reserved TCP port ranges:
netsh int ipv4 show excludedportrange protocol=tcp
On my machine, part of the output was:
2926 3025
3026 3125
Port 3000 clearly falls inside the reserved range 2926–3025.
Solution
Option 1 — Use Another Port
Pick a port outside the excluded ranges, e.g.:
app.listen(8848);
Option 2 — Remove the Exclusion
If you really need port 3000:
# Allow ports 3000–3019 for binding,should be run as Administrator
netsh int ipv4 delete excludedportrange protocol=tcp startport=3000 numberofports=20
⚠️ You might need to stop services that automatically reserve these ports (e.g., Hyper-V, Docker Desktop, some VPN clients) because they may re-reserve them on reboot.
Takeaway:
If Node/Express fails to bind to a seemingly “free” port with EACCES, check Windows excluded port ranges — it might not be your code at all.