Tailored quoteLeave a short request: we reply the same day and send a written quote within 1 business daySame-day reply · quote in 1 business dayGet a quote
Software

Localhost Refused to Connect? How to Fix ERR_CONNECTION_REFUSED

Talha Aslan 19 min read 4 views

Why does localhost refused to connect appear, and what should you do first?

Localhost refused to connect means your browser reached a port on your own computer, but no application there accepted the connection. The server is stopped, listening on a different port, or bound to a different address. Check the terminal first, then verify the address and port.

The order below runs from the most common cause to the rarest. In our experience, the first three steps fix most cases.

  1. Look at the terminal where you started the app. Confirm the server is running and has not crashed.
  2. Compare the port in the terminal with the port in the address bar.
  3. Try http://127.0.0.1:PORT and compare the result with localhost.
  4. Check whether the address starts with http or https.
  5. Find out whether another process already holds the port.
  6. If you use Docker, WSL or a virtual machine, inspect the port mapping.
  7. Leave the firewall, antivirus and browser cache for last.

This article solves this one error only. In practice, for neighboring problems, we link to our other guides.

What does this error message actually tell you?

Your browser sends a connection request to the host and port in the address bar. The operating system looks for a process listening on that port. Also, if it finds none, it rejects the request immediately, and the browser shows a message similar to ERR_CONNECTION_REFUSED. The exact wording changes between browsers and versions, so search for the error code instead.

There is one important distinction here. A refused connection means the request arrived, but nobody opened the door. A timeout means the request got no answer at all. If you hunt for a network blocker, a timeout is more likely. A refusal is almost always an application or address problem.

So refreshing your internet connection, flushing the DNS cache or restarting the router will not help. The traffic never leaves your machine in the first place.

What is the right diagnostic order when localhost refused to connect?

Our approach is specific: check this first, because it is the most common cause. Base your diagnosis on results, not guesses. In short, each step can make the next one unnecessary.

Example scenario: a teammate opens the front end project and sees that localhost refused to connect. The terminal shows no line saying the server started. In that case, port, address and Docker checks are pointless, because the server is simply not running.

  • Terminal output: did the server start, or did it print an error and exit?
  • Port number: is the port you typed the port the app listens on?
  • Listening address: does the app listen on IPv4 only, IPv6 only, or both?
  • Protocol: is it http or https?
  • Conflict: is another process holding the port?
  • Environment: is Docker, WSL or a virtual machine in the way?

In short, change one variable at a time and note the result. Put simply, if you change three things at once, you will not know which one worked.

Is the server actually running?

The most common cause is also the simplest. The server never started, or it crashed after starting. Your browser then shows exactly this error. That said, closing the terminal, rebooting the computer or a dependency error can all end the process.

Go back to the window where you started the app. A red error, an uncaught exception or a command that returns immediately tells you the server is down. Many frameworks also print the address they listen on. Specifically, if you cannot find that line, the problem is not the browser.

Watch mode adds one more trap. When you save a file, the dev server restarts itself. In practice, if the new code has a syntax error, the process dies. The address that worked a few seconds ago then starts refusing connections.

You can also test outside the browser. This command shows whether the server answers:

curl -v http://127.0.0.1:3000

Here 3000 is only an example port, so use your own. Also, if the command says the connection was refused, the problem is on the server side. If you get a response, the browser cache or the name resolution is involved.

Are you opening the right port?

The second most common cause is a port mismatch. In short, frameworks use different default ports, and a project setting or environment variable can change them. You type the old port out of habit, but the app waits on the new one.

The startup line in the terminal is the most reliable source. Put simply, copy the address from there and paste it into the browser. Copying also removes typos.

  • If you started the same project in two terminals, the second copy may have picked another port automatically.
  • The port value in an environment file overrides the default in the code.
  • An old bookmark or history entry may point to a port nobody uses anymore.
  • An address from a teammate may map to a different port on your machine.

Also remember that with a reverse proxy, the public port and the application port differ. Locally, you usually need the application port.

Which address is the app bound to: 127.0.0.1, 0.0.0.0 or ::1?

A server accepts connections only on the address it is bound to. 127.0.0.1 is the IPv4 loopback address of your own machine. ::1 is the IPv6 equivalent. 0.0.0.0 means all IPv4 interfaces.

According to the Node.js documentation, a server that listens without a host uses the unspecified IPv6 address when IPv6 is available, and the unspecified IPv4 address otherwise. On many systems, listening on IPv6 also covers IPv4, but this behavior is not identical everywhere. That said, see the Node.js net documentation for details.

The practical result is this: if the app listens only on 127.0.0.1 and the browser resolves the name localhost to ::1, the connection is refused. The reverse also happens: the app listens only on ::1, while the client tries IPv4.

So try both addresses by hand. If http://127.0.0.1:PORT works and http://localhost:PORT does not, the name resolution and the listening address do not match. The fix is to start the app so it listens on both IPv4 and IPv6, or to write the address as 127.0.0.1 explicitly.

Why does localhost resolve to an IPv6 address, and why does that break things?

Localhost is a name, not an address. Specifically, the operating system resolves it through the entries in the hosts file, often to both 127.0.0.1 and ::1. Which one the client tries first depends on the client and its version.

The Node.js documentation explains that newer versions can keep the order the operating system returns. Older versions preferred IPv4. So when you move a project to a newer Node.js version, a localhost address that worked before can suddenly refuse connections. In practice, check the current behavior in the Node.js dns documentation.

The easiest way to confirm this is to compare the two addresses. If IPv4 works and localhost does not, this is the likely cause. Also, for general background on the protocol, read our IPv6 guide.

You can also check your network with the free IPv6 test tool. However, that tool measures outside connectivity, not the local loopback. For local issues, look at the hosts file and the listening address of your app.

What happens when you mix up http and https on localhost?

If your server speaks plain http and you type https, the connection fails or you see a certificate error. Often the browser also shows the refused message. In short, one port cannot speak both protocols.

Some development tools enable https by default, and others do not. When you change one setting, the protocol changes too. Use the address the terminal prints instead of typing it by hand.

There is another trap in the address bar. Put simply, browsers can remember your earlier visits while autocompleting. For example, an address you opened with https last week may be suggested with https again, even though your app now starts with http. In that case, type the full address with the protocol.

If you need a secure connection for a local feature, use a tool that creates a certificate for local development. That said, for production certificates, read our SSL certificate guide.

Is another process using the port (EADDRINUSE)?

Two processes cannot listen on the same port at the same time. If a process already holds the port, your new app prints an error similar to EADDRINUSE and exits. When you then open the address, the connection is refused because nothing listens.

There are two different scenarios. In the first, an old process still holds the port, and the new server never starts. In the second, the old process hangs, and the browser talks to a stale or broken app.

Read the first red line in the terminal. Specifically, if it says the port is in use, the problem lies in another process. Maybe you forgot to close a previous session, and an old copy is still running in the background.

This class of error is not limited to your laptop. In practice, in production, a process manager prevents the same port from being started twice. Our guide on managing Node.js apps with PM2 explains how.

How do you find the process that uses a port?

The operating system can list every listening port and its owner. Also, the commands differ between systems, but the logic is the same: pick the port, find the owner, and stop the process if needed.

  • macOS and Linux: lsof -i :3000 shows the process holding the port and its ID.
  • Linux: ss -ltnp lists all listening TCP ports.
  • Windows: netstat -ano prints the process ID in the last column next to the port.

After you find the process ID, check which application owns it in the task manager or activity monitor. Do not stop a system process you do not recognize. In short, if it is your own old dev server, you can close it.

Alternatively, start your app on a different port. Most frameworks read the port from an environment variable or a command line option. Put simply, that gets you running before you solve the conflict. For a lasting fix, find out why the old process stayed alive.

Why does localhost refused to connect happen with Docker?

In Docker, the app runs inside a container with its own network space. That said, your browser runs on the host. The bridge between them is the port publishing setting. Specifically, without it, localhost refuses the connection.

The Docker documentation explains that you must publish a port when you start the container to reach it from the host. The general form pairs a host port with a container port:

docker run -p 8080:3000 image-name

In this example you open 8080 in the browser, while the container listens on 3000 inside. In practice, see the Docker port publishing documentation for details.

  • The EXPOSE line in a Dockerfile does not publish the port. It only documents it.
  • If the app inside the container listens only on 127.0.0.1, requests from outside never reach it. The app must listen on all interfaces.
  • To see the mapping of running containers, read the ports column in the docker ps output.

If you are new to Docker, start with our Docker containers guide. For database containers, our PostgreSQL and MySQL in Docker guide shows the same port logic.

How does localhost behave in WSL and virtual machines?

With WSL or a virtual machine, your app runs inside another operating system. Also, the browser usually runs on the host system. So localhost points to the machine where the browser lives, not the machine where the app lives.

Some setups forward ports from the virtual environment to the host automatically. Others do not, and you must use the virtual machine's own IP address. In short, the behavior depends on the version, the network mode and the settings. Therefore, check the official documentation of your setup.

  • Check the address the app listens on inside the virtual environment.
  • Verify the network mode of the virtual machine, such as bridged, NAT or host-only.
  • Add a port forwarding rule in the virtual machine settings if needed.
  • Open the browser inside the virtual environment too. If it works there, the problem is the network bridge.

The same applies to a remote server. If you run the app on a remote server and open localhost on your own computer, you are asking the wrong machine. Put simply, use the server's real address, or set up a secure port forwarding tunnel.

Which settings differ between Node.js, Python and PHP servers?

The browser shows the same message for all of them. The difference lies in the default listening address and in the startup message. That said, that is why you should read the documentation of your own framework.

Some local development servers listen only on the loopback address for safety. Others listen on all interfaces so other devices on the network can reach them. If the same project behaves differently on two machines, this default is often the reason.

  • If the start command accepts an address option, write the address explicitly.
  • When you pass the port and address through environment variables, confirm in the terminal output that the app reads them.
  • Debug mode and production mode may listen on different addresses, so note which mode you started.
  • If you run several projects, give each one its own port.

For example, if a teammate opens the same code without trouble, compare the Node.js or Python versions on both machines. A version difference can change name resolution. That way you quickly learn that the problem lies in the environment, not in the code.

What changes when you use a reverse proxy such as Nginx?

A reverse proxy forwards incoming requests to the app behind it. Specifically, if the app is down, the proxy usually returns a 502 style response. If the proxy itself is down, the browser shows a refused connection again.

Locally, you rarely need a proxy. Still, if you build a production-like setup, test both layers separately. First go straight to the app port, then go to the proxy port. In practice, the layer where the error starts is the problem layer.

So the backend address in the proxy configuration must match the real listening address of the app exactly. For example, if the proxy forwards to 127.0.0.1 while the app listens only on ::1, the request is refused. We describe a similar production case in our 502 Bad Gateway guide.

What does a three minute diagnosis look like? An example scenario

The flow below is purely an example scenario, not a real customer case. It shows how the order works in practice.

A developer opens the project and sees that localhost refused to connect. First, they look at the terminal and see the server start line. The server is running, so the cause must lie elsewhere.

Second, they compare the port in the terminal with the address bar, and both match. Also, third, they run curl against 127.0.0.1 and get a response. Then they try localhost, and the connection is refused.

The result is clear: localhost resolves to an IPv6 address, but the app listens only on IPv4. The developer writes the address as 127.0.0.1 and keeps working. In short, for a lasting fix, they add the listening address to the startup setting. The whole process takes a few minutes, and nobody changes a setting at random.

Can a firewall or antivirus block the connection?

Yes, but less often than you might think. Put simply, loopback traffic usually stays outside the firewall. Still, some corporate security tools restrict access to local ports.

That is why we put this step near the end of the list. First make sure the app and the address are correct. Then blame the security software.

  • Check the logs of the security software for blocked connections.
  • On a managed device, ask the IT team about the policy.
  • Instead of turning the firewall off, add a rule for your development server.
  • If you turn it off for a test, turn it back on as soon as you finish.

Browser extensions can also break access to local addresses. Try a private window without extensions. That said, if it works there, an extension is the cause.

If you are curious about server side firewall concepts, see our CSF firewall guide. For local development, you rarely need it.

Could the hosts file have broken the name localhost?

Yes, it could. Specifically, the operating system maps the name localhost to the loopback address through the hosts file. If you edited the file by hand, or a tool changed it for you, the name may point somewhere unexpected.

The file normally has one IPv4 line and one IPv6 line for localhost. In practice, if one of them is missing, the client may try the wrong address every time. If another line sends the name to a different IP, the request never reaches your own machine.

  • Open the file and read every line that mentions localhost.
  • Check whether the same name is defined on more than one line.
  • Restore any entries you commented out.
  • After a change, close the browser completely and reopen it.

However, this cause sits low on the list. Also, if the terminal, the port and the listening address are correct, and 127.0.0.1 works, the hosts file is the next place to look. A VPN or a local DNS tool can also change this behavior.

How do browser cache and HSTS affect a localhost error?

A browser sometimes remembers an earlier response or redirect. If it once saw a permanent https redirect for localhost, it may refuse to open the address over http. In short, the result is a connection that is still refused.

HSTS tells the browser to connect to a site only over https. If the same address once sent that header, the browser upgrades later http requests on its own. Put simply, read the details in the MDN HSTS documentation.

  • Try the same address in a private window. If it works there, the cache or a stored policy is the cause.
  • Try another browser.
  • Clear site data for localhost only.
  • If the HSTS entry persists, delete the localhost entry in the browser's domain security policy section.
  • Do not send the HSTS header in local development.

In short, the cache cause is rare, but it is confusing when it happens. If the terminal and curl look clean but the browser still refuses, suspect this entry.

Which symptom points to which cause?

The table below speeds up the diagnosis. Find your symptom, then apply the first check. That said, the order runs from most likely to least likely.

SymptomLikely causeFirst check
No server start line in the terminalServer is not running or crashedFirst error line in the terminal
Terminal says 3000, you typed 8080Port mismatchCopy the address from the terminal
127.0.0.1 works, localhost does notIPv4 and IPv6 address mismatchListening address of the app
Startup error says the port is in usePort held by another processFind the process holding the port
Container runs, browser cannot reach itPort not published, or app listens on the internal address onlyPorts column of docker ps
App runs in WSL or a virtual machineNetwork bridge does not forwardNetwork mode of the environment
Works in a private window, fails normallyCache, HSTS or extensionClear site data
Everything is correct, still refusedSecurity softwareSecurity software logs

How is this error different from CORS, timeout and memory errors?

Some errors look similar but have different fixes. You need to tell them apart so you do not knock on the wrong door.

  • Connection refused: The request arrived, and nobody listens. This article covers it.
  • Timeout: The request got no answer. It points to a network, routing or firewall problem.
  • CORS error: The server answered, but the browser blocked a cross origin request. See our guide on how to fix the CORS error.
  • Memory error: The server crashed because it ran out of memory. Our JavaScript heap out of memory guide helps here.

Therefore, look at the network tab and the terminal, not only at the first sentence in the browser. If the server never answered, fighting with CORS wastes your time. Specifically, if an answer came back, hunting for a refused connection is wrong.

We also recommend our guide on debugging techniques for developers for general habits.

Which habits prevent this error for good?

If you see the same error once a month, the problem is the setup, not you. A few small habits end most repeats.

  • Write the port number in the project documentation and in the example environment file, so everyone uses the same value.
  • Print the address and port in the server start message.
  • State the listening address explicitly instead of trusting the default.
  • Close running dev servers when you finish.
  • With Docker, keep the port mapping in a configuration file, not only on the command line.
  • Use the same Node.js version across the team, which reduces name resolution differences.

Also, a short checklist for every new developer solves the problem on day one. In practice, the same logic applies when you move to production. If you deploy a Node.js app to a Linux server, follow our Node.js deployment guide with Nginx and systemd.

What is the final checklist if nothing has worked yet?

If you applied every step and the error remains, repeat the list from the top, in order. Also, most of the time, one step was skipped too quickly.

  1. Confirm in the terminal that the server runs without errors.
  2. Check that the port you typed matches the port in the terminal.
  3. Run curl against 127.0.0.1.
  4. Try the localhost address separately and compare the results.
  5. Check whether the address uses http or https.
  6. Find the process that uses the port.
  7. Check the Docker, WSL or virtual machine mapping.
  8. Try a private window and another browser.
  9. Read the security software logs.

It also helps to write down what you find while you work. Note which address and port you used and what answer you got. In short, that way, the next time localhost refused to connect, you will not rethink the same steps. Your teammates benefit from the same notes too.

If you still have no solution, collect the error message, the terminal output and your environment in one place. Put simply, together, these three make it much easier for someone else to help you.

When should you get professional help with development environment problems?

A one-off port problem does not need outside help. However, if such interruptions repeat often in your team, the cause may be the process. Nonstandard setups, undocumented ports and environments where everyone works differently waste time.

At Talha Aslan and team, we care about reproducible development environments in custom software projects. That said, if you want to see scope and budget for your project, request a quote on our custom software development page.

Note: This article is a general diagnostic guide. Security policies on corporate networks or managed devices may differ, so ask your IT team.

Frequently Asked Questions

Does localhost refused to connect mean my internet is down?
No, it does not. This error means your request found nothing listening on a port of your own computer. The traffic never leaves your machine. Refreshing the router or flushing DNS will not solve it. Check that the server runs, that you typed the right port, and that the address matches the address the app listens on.
What should I do if 127.0.0.1 works but localhost does not?
Most likely, the name localhost resolves to an IPv6 address while your app listens only on IPv4. You have two options. Use 127.0.0.1 directly in the address, or configure the app to listen on both IPv4 and IPv6. Also check the entries in the hosts file and the version of your runtime.
How do I know another process uses my port?
Your app usually prints an error at startup saying the port is already in use. You can find the owner with lsof on macOS and Linux, or with netstat on Windows. The output shows a process ID. If it is your old dev server, close it. If you do not recognize it, start your app on another port.
Why does localhost not open when my Docker container is running?
The port may not be published to the host, or the app inside may listen only on the internal address. Map the host port to the container port when you start the container. Make sure the app listens on all interfaces. Confirm the mapping in the ports column of the docker ps output.
Can the browser cache really cause this error?
Yes, although rarely, and it makes diagnosis longer. An address you once opened with https and HSTS can force later http requests to https. Test in a private window or another browser. If it works there, clear the site data, and do not send the HSTS header during local development.
Will turning off the firewall fix localhost refused to connect?
Rarely. Local loopback traffic usually does not pass through the firewall. Some corporate security tools still restrict local ports. Instead of turning it off, add an allow rule for your development server. If you disable it for a test, enable it again right after, and rule out the other causes first.
  • localhost refused to connect
  • ERR_CONNECTION_REFUSED
  • EADDRINUSE
  • localhost error
  • Docker port mapping
  • Node.js
  • debugging
Share:
Talha Aslan

Google Partner digital marketing expert. Hands-on with SEO, Google Ads, web design and e-commerce projects since 2012; every post here comes from that experience.

Next project

Get a quote for your project.

Your brief goes straight to Talha Aslan and team: strategy led by Talha, delivery by an experienced team. We reply the same day and send the scope, timeline and price as a written quote within 1 business day.