Skip to content

503 Service Unavailable Through a Proxy: Who Sent It, and the Fix for Each

Who sent your 503: the proxy, a rate limiter or the site. The wording, the error your client prints and Retry-After, measured on October 23, 2026.

HProxy TeamAugust 24, 2026Updated October 23, 202610 min read

How to Fix 503 Service Unavailable Errors When Using a Proxy

A 503 means a server will not handle your request right now. Through a proxy, four kinds of machine can send it. The proxy itself can, when it cannot reach the site. A rate limiter can, when your address has used up its share. The site's edge can, and so can the site, when it is overloaded or down for maintenance.

Each one has a different fix, so the first job is to learn who answered. Two clues settle it. Each server writes its 503 page in its own words. And over https, your client reports a proxy's 503 in a different way from a site's. We measured that second clue on October 23, 2026, with curl, GNU Wget and Python requests against stub servers on our own machine.

What a 503 means

RFC 9110, the HTTP standard, defines 503 as a server that "is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay". The server may also send a Retry-After header to say how long to wait.

MDN adds a point worth keeping. A server that limits one client's rate should answer 429 Too Many Requests, it says. nginx's own rate limiter answers 503 instead, unless its owner sets another code.

Who sent it: read the words

Each server writes its 503 page in its own words, and people search for exactly those words:

Monthly searches for the words each server prints with its 503
503 Service Temporarily Unavailablenginx
22,200
The service is unavailableIIS on Windows
3,600
Backend fetch failedVarnish
2,400
No server is available to handle this requestHAProxy
1,900
nginx's wording draws 22,200 searches a month, six times the next one.
Source: Google Ads Keyword Planner, worldwide, English, 12-month averages, read October 23, 2026 · hproxy.comProxy.

The table pairs each wording with its author, from the server's own source code or documentation:

The page saysWho wrote itWhat it means
503 Service Temporarily UnavailablenginxIts built-in page. Also what its rate limiter sends by default
HTTP Error 503. The service is unavailable.IIS, through Windows' HTTP layerThe app pool is offline after errors, disabled, too busy, or its queue is full
Error 503 Backend fetch failed, with "Guru Meditation"VarnishThe cache could not reach the server behind it
No server is available to handle this request.HAProxyNo server behind the load balancer was available
Any 503 with "cloudflare" or "cloudflare-nginx" in the pageCloudflareCloudflare says the problem may be on its side
A 503 with none of theseOften the site's own appCheck the headers and the timing next

Cloudflare's rule comes from its own docs. A 503 with "cloudflare" or "cloudflare-nginx" in the HTML may stem from Cloudflare. One without those words came from the site's own server.

Over https, your client already tells you

Most scraping runs over https. Then your client asks the proxy for a tunnel with a CONNECT request, and the page travels inside that tunnel. That gives two very different 503s. The proxy can refuse the tunnel with 503. Or the tunnel opens and the site answers 503 inside it.

We built both cases on our own machine. Stub A, a proxy, answers every CONNECT with 503. Stub B opens the tunnel to a local https server that answers 503. Then we sent the same request through each with the clients already installed on three Linux systems.

Our own run on October 23, 2026, in Ubuntu 24.04 under WSL: stub proxies and a stub https server on 127.0.0.1, nothing outside the machine. Terminal capture.

Every client drew the line in the same place:

ClientThe proxy refused the tunnel with 503The site answered 503 inside the tunnel
curl 8.5.0, 8.14.1, 8.18.0Exit 56, "CONNECT tunnel failed, response 503"Exit 0, status 503
GNU Wget 1.21.4, 1.25.0Exit 4, "Proxy tunneling failed: Service Unavailable"Exit 8, "ERROR 503: Service Unavailable."
GNU Wget2 2.2.1Exit 4, "Failed to connect: Connect error"Exit 8, "HTTP ERROR response 503"
Python requests 2.31.0Raises ProxyError, "Tunnel connection failed: 503"Returns a response with status_code 503

So the rule is simple. If your code got a response object with status 503, the site's side sent it. If your code got a proxy or tunnel error that mentions 503, the proxy sent it, and the site never saw the request. curl can print both answers in one line:

curl -s -o /dev/null -w 'tunnel %{http_connect}, page %{http_code}\n' \
  -x http://YOUR-LOGIN:YOUR-PASSWORD@premium.hproxy.com:9000 https://example.com/

"tunnel 503, page 000" means the proxy refused. "tunnel 200, page 503" means the site answered 503. Curl 7.86.0 and older word the proxy's refusal as "Received HTTP code 503 from proxy after CONNECT", with the same exit code 56. Curl 8.20.0, released on April 29, 2026, kept today's words and moved the exit code to 7, so a script that checks for 56 should accept 7 as well. We read both changes in curl's own source.

For a plain http address there is no tunnel, and both 503s arrive as ordinary responses. Then read the page words above, and look for a Via header or a proxy's name in the Server header. Our 502 guide measured those headers and the timing in the same way.

The fix for each sender

The site or its edge is busy. Wait and send less. Read Retry-After and wait at least that long; without it, back off and add a little random delay. Cut the number of parallel requests to that host until it answers again.

A rate limiter answered. The pattern gives it away: a fresh address works for a while, then gets 503 at about the same count. Slow down per address, and spread the work over more addresses. The next sections cover both.

The proxy answered. Check the proxy before blaming the site. Our proxy checker shows whether it is alive and how fast it answers. A proxy that cannot reach a site may send 503 itself. A 2017 report on the Squid users' list describes Squid answering 503 at once when the site refused its connection. For a paid proxy, read its error page, and widen your targeting if the error names a location.

Cloudflare answered. Its docs point to a connectivity problem in one of its data centers. Wait, then try again.

The site is down. If the 503 follows you through every exit and from a direct connection too, stop. Queue the work and test with one request now and then. A scraper that keeps hitting an outage pays for traffic that returns nothing.

Which clients honor Retry-After

Retry-After only helps if your client reads it. So we pointed each client at a stub that answers every request with 503 and "Retry-After: 3", and logged when each request arrived:

Seconds before the first retry, when the server asked for 3
curl -⁠-⁠retry 38.5.0, 8.14.1 and 8.18.0
3 s
Python urllib3 Retryurllib3 2.0.7, through requests
3 s
GNU Wget -⁠-⁠tries=41.21.4 and 1.25.0
1 s
GNU Wget2 -⁠-⁠tries=42.2.1
1 s
curl and urllib3 waited the 3 seconds the server asked for; Wget and Wget2 waited 1.
Source: Our stub run on 127.0.0.1, October 23, 2026, in Ubuntu 24.04, Fedora 44 and Debian 13 under WSL · hproxy.comProxy.

The full run, three retries each:

Client and optionsRequests sentWaits between them
curl with no options1It reports the 503 and stops
curl --retry 343, 3 and 3 seconds
curl 8.5.0 --retry 3 -o /dev/null1Stopped with exit code 23 and no message
GNU Wget and Wget2, --tries=4 --retry-on-http-error=50341, 2 and 3 seconds
requests with no retry adapter1Returns the 503 to your code
requests with urllib3 Retry(total=3, status_forcelist=[503])43, 3 and 3 seconds, then RetryError
The same with respect_retry_after_header=False, backoff_factor=140, 2 and 4 seconds

Three results matter for scrapers. curl has followed Retry-After since version 7.66.0, its manual says, and our run agreed. GNU Wget kept its own backoff whatever the header said: 1 second after the first failure, 2 after the second, up to 10 seconds by default. And curl 8.5.0, the version in our Ubuntu 24.04, stopped at the first 503 with exit code 23 when its output went to /dev/null. With a real output file it retried normally, and curl 8.14.1 and 8.18.0 retried either way.

Scrapy retries 503 by default, per its docs, which list 503 in RETRY_HTTP_CODES. The docs say nothing about Retry-After, and we did not run Scrapy. Pair its retries with a download delay or AutoThrottle, as our Scrapy guide shows.

In Python, a requests session with urllib3's Retry does the waiting for you. urllib3 honors Retry-After by default on 413, 429 and 503:

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=4,
    status_forcelist=[503],
    backoff_factor=1,                 # used when no Retry-After comes back
    allowed_methods=["GET", "HEAD"],
)
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=retry))
session.proxies = {"https": "http://YOUR-LOGIN:YOUR-PASSWORD@premium.hproxy.com:9000"}

response = session.get("https://example.com/page", timeout=30)
print(response.status_code)

With curl, add --retry and keep a cap on the total time. Write to a real file, which also sidesteps the 8.5.0 trap:

curl --retry 4 --retry-max-time 120 -o page.html \
  -x http://YOUR-LOGIN:YOUR-PASSWORD@premium.hproxy.com:9000 https://example.com/page

When more addresses help

A rate limit tied to one address is the case where a pool of addresses helps. nginx shows how common that setup is. Its rate-limit module exists "in particular" to limit "requests coming from a single IP address", in its own words. Its example counts per client address, and its default answer to a request over the limit is 503.

Against a limit like that, find the pace at which the 503s start and stay below it on every address. Then add addresses to raise the total, rather than pushing one address harder. Our 429 guide works through the same arithmetic for sites that answer 429 instead.

Residential Premium gives each request a fresh residential IP by default. Some flows have to stay on one address. For those, a sticky line holds one exit for 3 minutes to 24 hours, as our guide to sticky and rotating sessions explains. It costs $1.49/GB for one GB, falling to $1.00/GB at 1,000 GB+.

More addresses do nothing for a site that is down, or for a 503 your proxy sends. Check those first, with the clues above.

503 next to 502 and 504

The three get confused because all three come from a server in the path. A 502 Bad Gateway means a gateway got an invalid answer from the server behind it. A 504 Gateway Timeout means the gateway got no answer in time. A 503 is a valid, prompt answer that says "not now". Our overview of every proxy error sorts all of them by which leg of the connection failed.

Sources

Frequently asked questions

What does 503 Service Unavailable mean?

RFC 9110 defines it as a server that is currently unable to handle the request because of a temporary overload or scheduled maintenance. The server may add a Retry-After header to say how long to wait. Any server in the path can send it, your proxy included.

Is the 503 from my proxy or from the website?

For an https address, your client tells you. In our test with curl, Wget and Python requests, a 503 from the proxy arrived as a failed tunnel: an error, with no status code from the site. A 503 from the site arrived as an ordinary response with status 503. For a plain http address, read the body and the headers.

What does 'CONNECT tunnel failed, response 503' mean?

It is curl's message when the proxy answered your CONNECT request with 503. The proxy refused to open the tunnel, so the site never saw your request. curl 8.19.0 and older exit with code 56, curl 8.20.0 and newer with 7, and the http_connect variable holds the 503. Curl 7.86.0 and older print 'Received HTTP code 503 from proxy after CONNECT' for the same thing.

What does 'Backend fetch failed' mean?

It is the 503 page of Varnish, a cache that sits in front of many sites. Varnish Software's own guide says the page reports that Varnish could not reach the backend, the server behind it. The site has a problem; your proxy did nothing wrong.

What does 'No server is available to handle this request' mean?

It is the built-in 503 page of HAProxy, a load balancer, word for word from its source code. It means no server behind that load balancer was available for your request.

What is the Retry-After header?

A header a server may send with a 503 to say how long the service is expected to stay unavailable, as a number of seconds or as a date. In our test, curl's --retry and Python's urllib3 Retry waited the time it asked for. GNU Wget and Wget2 used their own backoff of 1, 2 and 3 seconds.

Why do I get 503 only through a proxy?

Often a rate limit tied to the address. nginx's rate limiter answers 503 unless it is told otherwise, and its own example counts requests per client address, so a busy shared address meets it first. A proxy can also send 503 itself when it cannot reach the site.

Proxies that don't die mid-job

Residential, ISP, datacenter and mobile, verified by the same engine that runs tens of millions of checks. They read as a real device and hold up under load. Pay as you go, and your balance never expires. $0.44/GB is the 2,000 GB+ rate; a single gigabyte is $0.50/GB, with no minimum order.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed