Proxy error codes are HTTP status codes and client errors that come from one of two places: the proxy server you connect through, or the website behind it. 407 always comes from the proxy. 403, 429 and 503 usually come from the target site. 502 and 504 mean the proxy could not get a good answer from the target in time. To tell them apart, run the request with curl -v: an error in reply to the CONNECT line is the proxy's; an error after CONNECT tunnel established is the website's.

That one distinction decides the fix. Changing credentials will not cure a rate limit, and slowing down will not cure a typo in a port number. The table below is the quick lookup; the sections after it take each proxy error code in turn, with the commands to confirm and fix it.

Proxy error codes: quick lookup table

Code or messageUsually sent byWhat it meansFirst thing to try
407 Proxy Authentication RequiredProxyMissing or wrong proxy credentialsRecopy username and password from the order; URL-encode special characters
403 ForbiddenTarget (sometimes proxy)Request refused: IP reputation, fingerprint, geography, or a proxy access ruleCompare with and without the proxy; check headers and IP type
429 Too Many RequestsTargetYou are over the site's rate limitBack off, honour Retry-After, lower concurrency per IP
502 Bad GatewayProxyThe proxy got no valid answer upstream (DNS failure, refused connection)Check the target hostname resolves; retry on another IP
503 Service UnavailableTarget (sometimes proxy)Target overloaded or challenging you; or the proxy has no capacityLook at the body: a challenge page means a block, not an outage
504 Gateway TimeoutProxyThe target took too long to answer the proxyRaise the read timeout; test the target directly
ERR_PROXY_CONNECTION_FAILEDBrowserThe browser cannot reach the proxy at allCheck host and port with curl -v or nc -vz
CONNECT tunnel failed, response NProxyThe proxy refused to open an HTTPS tunnel; N is its reasonRead N and jump to that code's section
SSL/TLS errorsYour client or the targetWrong proxy scheme, bad target certificate, or TLS interceptionUse http:// for the proxy URL; inspect the certificate chain

How to tell if the proxy or the target sent the error

For HTTPS targets (nearly all of them today), your client first asks the proxy to open a tunnel with an HTTP CONNECT request. The proxy answers that request itself. Once it says 200 Connection established, everything that follows is encrypted end to end between you and the website, and the proxy can no longer read or rewrite it. So the position of the error in the exchange tells you who sent it.

Here is a 407 from a local test proxy, run with bad credentials:

curl -v -x http://USERNAME:WRONG@HOST:PORT https://httpbin.org/ip
> CONNECT httpbin.org:443 HTTP/1.1
< HTTP/1.1 407 Proxy Authentication Required
< Proxy-Authenticate: Basic
< Connection: close
* CONNECT tunnel failed, response 407

The 407 is the reply to CONNECT, and it carries a Proxy-Authenticate header, which only a proxy sends. Compare a 429 through the same proxy with correct credentials:

> CONNECT httpbin.org:443 HTTP/1.1
< HTTP/1.1 200 Connection established
* CONNECT tunnel established, response 200
< HTTP/2 429
< server: gunicorn/19.9.0

The tunnel opened, then the target's own server (note its server header) answered 429. Nothing about the proxy needs fixing here. Three signals help:

  1. Position. Reply to CONNECT means proxy. After the tunnel means target.
  2. Headers. Proxy-Authenticate, and often a Via or proxy-software header, point at the proxy. The target's Server header and cookies point at the site. Header names vary by proxy software, so treat them as hints.
  3. Plain HTTP targets. For http:// URLs there is no tunnel: the proxy forwards the request and could return either its own error or the target's. Headers are your only clue there, which is one more reason to test against an HTTPS endpoint.

In Python, requests makes the same split for you. A refused CONNECT raises requests.exceptions.ProxyError with the proxy's status in the message (Tunnel connection failed: 407 Proxy Authentication Required), while a target's error comes back as an ordinary response with a status code. This small script classifies a URL; we ran it against a local authenticating proxy for every case in this article:

import os
import sys

import requests

PROXY = os.environ["PROXY_URL"]


def diagnose(url):
    try:
        resp = requests.get(url, proxies={"http": PROXY, "https": PROXY}, timeout=(5, 20))
    except requests.exceptions.ProxyError as exc:
        return f"PROXY: {exc}"
    except requests.exceptions.SSLError as exc:
        return f"TLS: {exc}"
    except requests.exceptions.ConnectTimeout:
        return "TIMEOUT while connecting"
    except requests.exceptions.ReadTimeout:
        return "TIMEOUT waiting for the response"
    if resp.status_code == 407:
        return f"PROXY: 407, Proxy-Authenticate={resp.headers.get('Proxy-Authenticate')}"
    return f"TARGET: {resp.status_code} (Server: {resp.headers.get('Server')})"


if __name__ == "__main__":
    for url in sys.argv[1:]:
        print(url, "->", diagnose(url))
export PROXY_URL="http://USERNAME:PASSWORD@HOST:PORT"
python diagnose.py https://httpbin.org/status/429 https://api.ipify.org?format=json

Copy HOST, PORT, USERNAME and PASSWORD from your order in the dashboard. On ProxyHive, each ISP or datacenter IP is its own endpoint with its own ports, as described in the docs.

407 Proxy Authentication Required

Sent by: the proxy, always. RFC 9110 defines it as the proxy's version of 401: you must authenticate with the proxy before it forwards anything.

Likely causes:

  • A wrong or stale username or password, often from copying the wrong order.
  • Special characters in the password (@, :, #, /, %) that break the proxy URL because they were not URL-encoded.
  • The order is set to IP allowlist authentication and your public IP has changed (home connections and CI runners change IPs often).
  • The client never sends credentials for HTTPS. Chrome, for example, ignores credentials in --proxy-server and asks in a dialog instead.

Fixes:

Pass the credentials separately so nothing needs encoding, and confirm the proxy accepts them:

curl -v -x http://HOST:PORT -U "USERNAME:PASSWORD" https://api.ipify.org?format=json

If that works but your code does not, encode the credentials when you build the URL:

from urllib.parse import quote

proxy = f"http://{quote(USERNAME, safe='')}:{quote(PASSWORD, safe='')}@{HOST}:{PORT}"

If the order uses an allowlist, check your current address with curl https://api.ipify.org (without the proxy) and compare it with the allowlist on the order.

403 Forbidden through a proxy

Sent by: usually the target; occasionally the proxy.

A 403 after the tunnel opened is the website refusing you. Common reasons are the reputation of the IP range (datacenter ranges are the first to be refused by strict sites), a request fingerprint that does not look like a browser, a geographic restriction, or a login wall. A 403 in reply to CONNECT is the proxy's own access rule: many proxies refuse tunnels to ports other than 443, or to destinations their policy blocks.

How to confirm: run the same request without the proxy and through it. If both fail, the proxy is not the problem. If only the proxied request fails, check what the site sees:

curl -x http://USERNAME:PASSWORD@HOST:PORT https://api.ipify.org?format=json
curl -x http://USERNAME:PASSWORD@HOST:PORT https://httpbin.org/headers

Fixes: send realistic headers, slow down, and match the IP type to the target: an ISP IP registered to a consumer carrier is refused less often than a datacenter IP on sites that check the network type. Our guide on how to avoid getting blocked while scraping covers headers, fingerprints and pacing in depth. If the target forbids automated access in its terms, a different IP will not change that, and our allowed-use policy sets out what we permit.

429 Too Many Requests

Sent by: the target, almost always. Defined in RFC 6585, it means you sent more requests than the site allows in a window. The response may include a Retry-After header, either in seconds or as a date.

Likely causes: too many requests per second, too many concurrent connections from one IP, or a burst at startup when every worker fires at once.

Fixes:

  1. Honour Retry-After when present. Otherwise back off exponentially with random jitter.
  2. Cap concurrency per IP, not only overall.
  3. Spread load across more IPs only after pacing is sane. Rotating through ten IPs at the same aggressive rate gets ten IPs rate limited.

Some proxy providers also answer CONNECT with 429 when you exceed their own connection limits. The position test above tells you which limit you hit. If you run a list of static IPs, rotating proxies in Python shows how to spread requests across them and bench the ones that keep failing.

502 Bad Gateway from a proxy

Sent by: the proxy. It tried to reach the target and got nothing usable: the hostname did not resolve, the target refused the connection, or the upstream connection dropped mid-response.

Here is a real 502 from a local proxy asked to tunnel to a hostname that does not exist:

* Establish HTTP proxy tunnel to no-such-host.invalid:443
< HTTP/1.1 502 Bad Gateway
* CONNECT tunnel failed, response 502

Fixes:

  1. Check the hostname for typos and confirm it resolves: dig +short example.com.
  2. Request the target without the proxy. If it is down for everyone, wait.
  3. Retry through a different IP. A 502 that follows one exit IP and not others points at that path.
  4. If you use SOCKS5, remember the difference between socks5:// (your machine resolves DNS) and socks5h:// (the proxy resolves it). Our HTTP vs SOCKS5 comparison explains when that matters.

503 Service Unavailable

Sent by: usually the target, sometimes the proxy.

From the target, a 503 means it is overloaded, in maintenance, or, very often, serving a bot challenge with a 503 status. Read the body before you conclude the site is down: a page mentioning a browser check or a CAPTCHA is a block, and the fix is the same as for 403. From the proxy, a 503 in reply to CONNECT means it had no capacity or no upstream route for that request.

Fixes: save the response body and look at it; retry later with backoff for real outages; treat challenge pages as blocks.

curl -s -o body.html -w "%{http_code}\n" -x http://USERNAME:PASSWORD@HOST:PORT https://example.com/
grep -iE "captcha|challenge|unusual traffic" body.html

504 Gateway Timeout

Sent by: the proxy. It connected to the target, or tried to, and gave up waiting before an answer arrived.

Likely causes: a slow target (heavy search pages, reports), a target far from the proxy's location, or a target that slow-walks suspected bots instead of blocking them.

Fixes: time the target directly with curl -w "%{time_total}\n" -o /dev/null -s https://example.com/; raise your client's read timeout for slow pages while keeping the connect timeout short; choose an IP closer to the target, which static ISP and datacenter IPs let you do by country and city.

ERR_PROXY_CONNECTION_FAILED and other browser errors

ERR_PROXY_CONNECTION_FAILED is Chrome's message for "I could not connect to the proxy server". No request reached any website. Its cousin ERR_TUNNEL_CONNECTION_FAILED means Chrome reached the proxy but the CONNECT was refused, which usually hides a 407, 403 or 502.

Likely causes: a wrong host or port, a proxy port blocked by a corporate firewall, an IP allowlist that does not include your address, or a stale system proxy left behind by a VPN client or an extension you removed.

Fixes:

nc -vz HOST PORT
curl -v -x http://USERNAME:PASSWORD@HOST:PORT https://api.ipify.org?format=json

If nc cannot connect, no browser setting will help: check the host, port and your network. If curl works and the browser does not, the problem is the browser's proxy configuration. On Windows, netsh winhttp show proxy shows the system-level WinHTTP proxy. Our setup guides for the Windows proxy settings and SwitchyOmega in Chrome walk through each screen.

SSL errors through a proxy

TLS errors through a proxy come in three flavours, and turning off certificate verification hides all three.

1. The proxy URL uses the wrong scheme. Writing https://HOST:PORT for a proxy that listens for plain HTTP makes your client try TLS with the proxy itself. curl reports (35) SSL_connect errors or "wrong version number"; Python may hang or raise a ProxyError. The fix is http:// in the proxy URL, even for HTTPS targets: the target's TLS runs inside the tunnel regardless.

2. The target's certificate is bad. curl's (60) SSL certificate problem: certificate has expired came from the target, through a working tunnel. Test without the proxy to confirm; it is not the proxy's fault.

3. Something intercepts TLS. Corporate proxies and some antivirus tools decrypt traffic and re-sign it with their own certificate authority. Check who issued the certificate you receive:

openssl s_client -proxy HOST:PORT -proxy_user USERNAME -proxy_pass pass:PASSWORD \
  -connect example.com:443 -servername example.com </dev/null 2>/dev/null | grep -E "subject=|issuer="

If the issuer is not a public certificate authority you recognise, the path is intercepted. Install that authority where your client trusts it, or route around the interception.

CONNECT tunnel failed

curl: (56) CONNECT tunnel failed, response 407 is curl telling you the proxy refused the tunnel, and the number is the proxy's status code. Read it and go to that section: 407 for credentials, 403 for a proxy rule (often a non-443 port), 502 for an unreachable target, 503 for capacity.

The other curl exit codes you will meet around proxies, all reproduced in our tests, are listed in the libcurl error reference:

curl exitMessageMeaning
5Could not resolve proxyThe proxy hostname does not resolve: typo or DNS problem
7Failed to connect ... Couldn't connect to serverNothing listens on that host and port, or a firewall refuses it
28Timeout was reachedPackets are dropped on the way to the proxy, or the target is slow
35SSL_connect errorUsually https:// in the proxy URL for a plain HTTP proxy
56CONNECT tunnel failed, response NThe proxy refused the tunnel with status N
60SSL certificate problemThe target's certificate failed verification

Before you contact support

When the error is on the proxy side, a good report gets a fast answer. Collect:

  1. The full curl -v output for one failing request, with the password removed.
  2. The time of the failure, with timezone.
  3. The target hostname and whether it fails without the proxy.
  4. The IP echo result: curl -x ... https://api.ipify.org?format=json.
  5. Whether every IP on the order fails or only one.

With that, a person on our support rotation can tell you in one reply whether the problem is the order, the network or the target. The curl setup guide has the flags used throughout this article.