What the error actually says

Chrome shows “This site can’t be reached. The connection was reset.” with the code ERR_CONNECTION_RESET (internally net error -101). Firefox says “The connection was reset”, or PR_CONNECT_RESET_ERROR when it happens during the TLS handshake. Programs see the same thing as ECONNRESET, “Connection reset by peer”.

On the wire, this is a TCP packet with the RST flag. A normal close is polite: each side sends FIN, data already in flight still gets delivered. A RST is the opposite. It means “forget this connection now”, and whatever was in the buffers is thrown away. The browser was waiting for a response and got told the conversation never happened.

The important word is after. The connection had opened. That single fact separates this error from its two siblings, and it is the quickest way to the cause:

ErrorWhat happened to the connectionHow it feelsWhere to look
ERR_CONNECTION_REFUSEDThe first packet (SYN) was answered with a RSTFails immediatelyNothing listening on that port, or a firewall that rejects
ERR_CONNECTION_TIMED_OUTThe first packet got no answer at allHangs, then failsFirewall that drops, wrong IP, routing
ERR_CONNECTION_RESETOpened fine, then a RST arrivedStarts loading, or fails a moment after connectingApplication, proxy, or a filter that reads the traffic

A reset almost always comes from something that looked at the connection and decided to kill it: the server process, a load balancer, a firewall that inspects traffic, or security software on your own machine. Your job is to work out which of these it was, and the fastest way is to change one thing at a time.

First: where does it happen?

Two questions sort most cases in a minute.

One site, or every site? If every HTTPS site resets, the problem is on your computer or your router. Skip to “Software on your own computer” below. If it’s one site, keep going.

One network, or every network? Load the same URL on your phone with Wi-Fi turned off. If it works on mobile data and fails on your Wi-Fi, the reset is coming from your network (office, school, ISP or country filter), not from the site. If it fails everywhere, the site itself is resetting, and only its owner can fix it.

You can also ask from outside your network entirely: the HTTP check fetches the page from DechoNet’s servers. If it loads there and not for you, the server is fine.

If you’re a visitor

Software on your own computer

Antivirus suites with “web protection” or “HTTPS scanning”, VPN clients, and corporate endpoint agents all insert themselves into your connections. When they decide a connection is suspicious, or simply fail, a reset is a common result. The same goes for the online-security programs that banking and government sites in some countries ask you to install.

Turn them off one at a time and retry. If disabling HTTPS scanning fixes it, leave that feature off or add an exception rather than uninstalling the whole product.

Check for a system proxy too. On Windows: Settings → Network & Internet → Proxy. On macOS: System Settings → Network → your connection → Details → Proxies. A proxy you don’t recognise is worth removing.

On Windows, if resets started after uninstalling security or VPN software, the network stack may be left with a broken component. netsh winsock reset in an administrator command prompt, followed by a reboot, restores the default Winsock catalog. It’s rarely the fix, but it’s the right last step before blaming the site.

Network filters: office, school, ISP, country

Web filters don’t need to decrypt HTTPS to block a site. At the start of every HTTPS connection, the browser sends the site’s name in plain text in the TLS ClientHello (the SNI field). A filter on the path reads it, and if the name is on its list, it sends a forged RST to your browser, sometimes to the server too. From your side it looks exactly as if the server reset you.

This is how many company and school firewalls work, and how some national filters work: South Korea, for example, has filtered HTTPS sites by SNI since 2019. Depending on the network, a blocked site shows up as a reset or as a hang.

Signs you’re looking at a filter rather than the site:

  • It works on mobile data or from the HTTP check, and fails on one particular network.
  • It fails instantly after connecting, every time, on the first request.
  • Other sites on the same server or CDN work.

There’s no fix you can make from your browser. Ask the network’s administrator, who can see why it was blocked. If you own the site and a filter is blocking it by mistake, the filter vendor usually has a recategorisation request form.

Clearing things that don’t matter

Clearing cookies and cache rarely fixes a reset. The reset happens at the TCP level, before the browser sends or reads anything that’s cached. Try it once if you like, but don’t spend long on it.

If you run the site

Start by reproducing it with curl from a machine that isn’t on a filtered network, and note when the reset happens:

curl -v https://www.example.com/ -o /dev/null

Reset during the TLS handshake:

* Connected to www.example.com (203.0.113.10) port 443
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* Recv failure: Connection reset by peer
curl: (35) Recv failure: Connection reset by peer

Reset after the request was sent:

> GET / HTTP/1.1
> Host: www.example.com
...
* Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer

The exact wording differs between curl versions and TLS libraries, but the split is what matters. A reset during the handshake points at the TLS layer or something filtering by SNI. A reset after the request points at the application or the proxy in front of it.

Also compare with curl: (52) Empty reply from server. That’s a normal close (FIN) with no response, which Chrome shows as ERR_EMPTY_RESPONSE. It has similar causes but is a different signal: the peer closed politely instead of aborting.

The process died mid-request

If the application crashes, or the kernel’s OOM killer ends it, the kernel closes its sockets. When unread data is sitting in the receive buffer, closing sends a RST rather than a FIN, so the client sees a reset.

Look at the moment of the failure:

journalctl -u myapp --since "10 min ago"
dmesg -T | grep -i -E 'out of memory|killed process'

A restart loop (systemctl status myapp showing a recent start time and a climbing restart counter) tells the same story. Fix the crash or the memory limit; there’s nothing to tune on the network side.

Large uploads reset instead of returning 413

A classic one. The client starts uploading a file larger than the server allows. The server decides to reject it, sends its 413 response, and closes the connection while the client is still sending. The unread upload data in the server’s buffer turns that close into a RST, and the browser shows ERR_CONNECTION_RESET instead of the 413 page. Servers try to soften this by reading and discarding the rest of the upload for a while before closing (nginx calls it lingering close), but with a big file, a slow link or another proxy in between, the reset still gets through often enough.

If resets only happen on uploads, check the body size limit at every layer: client_max_body_size in nginx (default 1 MB), LimitRequestBody in Apache, the limit on your load balancer or CDN, and the framework’s own upload limit.

sudo nginx -T | grep -n client_max_body_size

The app inside a container listens on 127.0.0.1

You publish a port with Docker (-p 8080:3000), but the app inside the container listens on 127.0.0.1:3000. The container’s loopback isn’t reachable through the published port. Depending on how the traffic reaches the container, this shows up as a reset, an empty reply, or a refusal rather than a clean error.

Make the app listen on 0.0.0.0 inside the container. Then docker port <container> and ss -ltnp on the host should agree on what’s exposed.

Idle connections killed by a load balancer or NAT

Load balancers, NAT gateways and stateful firewalls forget connections that have been idle for longer than their timeout. When either side later sends on that connection, the device has no record of it and may answer with a RST. AWS documents this behaviour for its Network Load Balancer, for example.

Browsers mostly hide this, because they retry a request that fails on a reused keep-alive connection. It surfaces in other clients: ECONNRESET in Node, ConnectionResetError in Python, “connection reset by peer” in Go, usually after a quiet period. The fix is to make the application’s keep-alive timeout shorter than the shortest idle timeout on the path, or to enable TCP keepalives so the connection never looks idle.

A firewall, WAF or DDoS protection in front of you

Security appliances in front of the server reset connections they don’t like: requests that match a WAF rule, clients over a rate limit, TLS ClientHellos they can’t parse. If resets cluster around certain URLs, payloads or client IPs, check the logs of whatever sits in front of the origin before you touch the application.

Finding out who actually sent the RST

When you can’t tell whether the server or something in between sent the reset, capture it on the server:

sudo tcpdump -ni any -v 'tcp port 443 and (tcp[tcpflags] & tcp-rst != 0)'

If the server sent the RST, you’ll see it leaving the server. If the client got a reset and the server’s capture shows nothing, something on the path sent it. Capturing on the client side helps too: a forged RST often arrives with a different IP TTL from the server’s real packets on the same connection, because it was sent from a box that’s fewer hops away.

Checking from outside with DechoNet

  • The HTTP check loads the URL from outside your network and shows the status, redirect chain and headers. If it succeeds while your browser resets, the problem is local to you or your network. When the request gets no answer from DechoNet’s overseas egress, the check retries from an observation point in Seoul, which helps with sites that block foreign IPs.
  • The port check tells you whether the TCP handshake on 443 completes at all. “Open” with your browser still resetting means TCP is fine and the trouble is in TLS, the application or a filter. One limitation: the port check reports refused, reset and no answer within 3 seconds all as “Closed”, so it can’t tell those apart. And hosts on Cloudflare IP addresses can’t be checked from our side at all; the tool says so instead of guessing.
  • A DNS lookup confirms the name points where you think. After a migration, an old IP can still be answering with a server that resets unknown hosts.

Searched for ERR_SSL_PROTOCOL_ERROR?

It’s a different error that turns up in the same situations. ERR_SSL_PROTOCOL_ERROR means the TLS handshake failed with a protocol error rather than a reset: the server sent something that isn’t valid TLS, or rejected the handshake. The two common causes overlap with this page. Security software or a filter interfering with HTTPS gives either error, and a server answering plain HTTP on a port the browser expects to be HTTPS gives the protocol error. The full walkthrough is in ERR_SSL_PROTOCOL_ERROR.

  • ERR_CONNECTION_REFUSED: the first packet was answered with a reset, so the connection never opened.
  • ERR_CONNECTION_TIMED_OUT: no answer at all, usually a firewall that drops or a wrong IP.
  • 502 Bad Gateway: you reached a proxy, and the proxy’s connection to the application failed. A reset between them shows up as 502, not as a browser error.

Check your own domain now

Free, no sign-up. Runs the exact check this guide describes and shows what to fix.