“localhost refused to connect”: how to find the cause in a minute
“Refused” is good news in disguise: your computer answered straight away and said nothing is listening there. So the fix is to find where your server actually is.
What “refused” means
When the browser connects to localhost:3000, the operating system checks whether any program is listening on port 3000. If none is, it immediately answers with a reset: ERR_CONNECTION_REFUSED in Chrome, “Unable to connect” in Firefox, ECONNREFUSED in Node, Connection refused in curl. It is different from a timeout (something in between dropped the packets, usually a firewall) and from an error page (the server is fine, your code isn't). Want the full trip a request makes? Wirebook's “What happens when you open a web page?” lesson walks through it.
The one-minute checklist
- Is the server running? Look at the terminal. A crash on start-up (a syntax error, a missing package, a missing
.envvalue) often scrolls past and leaves nothing listening. - Right port? Copy the URL the server printed rather than typing from memory. Vite uses 5173, Next.js and Create React App 3000, Angular 4200, Flask 5000, Django 8000. If the port was busy, many tools quietly pick the next one (3001, 5174).
- http, not https. Dev servers usually speak plain http. Typing
https://localhost:3000fails, and so can a browser that auto-upgrades to https. - Which address is it bound to?
localhostcan resolve to IPv6::1first. A server bound only to127.0.0.1then refuses connections on::1, or the other way round. Try bothhttp://127.0.0.1:3000andhttp://[::1]:3000; Node 17+ changed which one it prefers, which is a common surprise. - Is it really listening? Ask the OS (below). No line for your port means the server isn't up, whatever the terminal says.
See what is listening
| System | Command |
|---|---|
| Linux | ss -ltnp | grep 3000 |
| macOS | lsof -nP -iTCP:3000 -sTCP:LISTEN |
| Windows | netstat -ano | findstr :3000 |
| Any | curl -v http://127.0.0.1:3000/ |
Read the address column: 127.0.0.1:3000 accepts only local connections, 0.0.0.0:3000 or *:3000 accepts all, [::1]:3000 is IPv6 only.
Docker, WSL, VMs and phones
- Docker: publish the port,
docker run -p 3000:3000 …orports: ["3000:3000"]in Compose, and make the app listen on0.0.0.0inside the container. A server on the container's own127.0.0.1is unreachable from your machine even when the port is published. Inside a container,localhostmeans the container itself, so reach a database on your computer withhost.docker.internal. - WSL 2: Windows usually forwards
localhostto WSL, but if not, bind to0.0.0.0and use the WSL IP fromhostname -I. - Phone on the same Wi-Fi:
localhoston the phone is the phone. Use your computer's LAN IP, start the dev server with its host flag (vite --host,next dev -H 0.0.0.0,flask run --host=0.0.0.0) and allow it through the firewall.
“Address already in use” instead?
That's the opposite problem: something else holds the port, often an old copy of your own server (full walkthrough: EADDRINUSE). Find its process ID with the commands above and stop it (kill PID on macOS and Linux, taskkill /PID n /F on Windows), or start on another port.
Once it connects but answers with an error code, the 401 vs 403 and CORS guides pick up from there.
If the connection works but you get SSL wrong version number, you are using https:// on a plain-HTTP port: see SSL wrong version number.
Does the error mention ::1, or does 127.0.0.1 work while localhost doesn’t? That’s IPv6 vs IPv4: see ECONNREFUSED ::1. Remote SSH timing out rather than a local port refusing? See ssh Connection timed out. Name will not resolve at all (ERR_NAME_NOT_RESOLVED / NXDOMAIN)? See ERR_NAME_NOT_RESOLVED.
Related
Which port is my dev server on? · ERR_EMPTY_RESPONSE · Cloudflare Error 523 · ssh Connection refused port 22 · TypeError: fetch failed (Node) · net::ERR_CONNECTION_TIMED_OUT · HTTP 503 Service Unavailable · ETIMEDOUT / connect ETIMEDOUT · getaddrinfo ENOTFOUND · WebSocket connection failed
Questions
What does ERR_CONNECTION_REFUSED mean on localhost?
Your computer has nothing listening on that port and address. The server isn't running, is on a different port, or is bound to a different address (IPv4 vs IPv6, or inside Docker).
Why does 127.0.0.1 work but localhost doesn't?
localhost may resolve to the IPv6 address ::1 first, and your server listens only on IPv4 127.0.0.1. Use 127.0.0.1 in the URL, or make the server listen on both.
Why can't I reach my Docker app on localhost?
Either the port isn't published with -p or ports:, or the app inside the container listens on 127.0.0.1. It must listen on 0.0.0.0 so the published port can reach it.
How do I open my localhost site on my phone?
Use your computer's local network IP instead of localhost, start the dev server with its host option so it listens on all interfaces, and allow the port in your computer's firewall.
Published · updated .