Proxy error codes explained: 407, 403, 429, 502, 503, 504 and how to fix each
Proxy errors come from two places: the proxy and the website behind it. How to tell which one answered in ten seconds, what every status code and SOCKS5 reply means, and the fix for each, with the exact messages curl, Python and Chrome print.

A 407 is always the proxy. A 403 can come from either side. Knowing which one answered is half the fix, because the cures are opposite: a proxy error means your setup is wrong, a website error means the site does not like the request. Below: a quick test that tells them apart, then every status code and connection error you are likely to meet, each with its fix.
The messages quoted below were captured with curl 8.19, Python Requests 2.34, Scrapy 2.19 and Chrome 155 driven by Playwright 1.64 and Puppeteer 25.
First: did the proxy answer, or the website?
When you request an https:// URL through an HTTP proxy, your client first asks the proxy to open a tunnel with a CONNECT request. The proxy answers that request itself: 200 means the tunnel is open, anything else means it refused. Once the tunnel is open, TLS runs end to end between you and the site, so the proxy can no longer see or change anything. Every status code after that point comes from the website.
curl can print both answers at once:
curl -s -o /dev/null -x http://USERNAME:[email protected]:8080 -w "proxy: %{http_connect} site: %{http_code}\n" https://example.comHow to read the output:
proxy: 200 site: 200: everything works.proxy: 200 site: 403: the proxy did its job; the website blocked the request.proxy: 407 site: 000: the proxy refused your credentials and the website was never contacted.proxy: 502 site: 000: the proxy could not open the tunnel to the site.
With a plain http:// URL there is no tunnel. The proxy forwards the request and relays the answer, so a status can come from either side and %{http_connect} prints 000. When you are debugging, always test with an https:// URL.
Python Requests draws the same line for you. A proxy refusal on an HTTPS URL raises an exception, while a website refusal comes back as a normal response:
requests.exceptions.ProxyError: ... (Caused by ProxyError('Unable to connect to proxy', OSError('Tunnel connection failed: 407 Proxy Authentication Required')))One trap: on an http:// URL, a 407 does not raise. It comes back as a response with status_code == 407, so check the status.
407 Proxy Authentication Required
The proxy did not accept the credentials it received, or received none. It is the most common proxy error by far, and it is almost never an outage.
The usual causes:
- A typo, or invisible whitespace copied along with the username or password.
- A password with characters such as
@,:,/or#pasted raw into a proxy URL. The URL parser splits it in the wrong place. - Targeting options (
-country-us,-session-abc123) added to the password instead of the username. - A client that never sends credentials. Chrome ignores a username and password written into
--proxy-server. - The plan ran out of traffic or expired. Providers handle this differently, so when errors start suddenly after working fine, check the plan page first.
The fix is to copy the string fresh from the dashboard and to percent-encode the password if it goes inside a URL: @ becomes %40, : becomes %3A, / becomes %2F, # becomes %23. In curl you can skip encoding entirely by passing credentials separately with -U USERNAME:PASSWORD.
What a 407 looks like in each client. Puppeteer and Playwright report Chrome's error codes with a net:: prefix:
- curl:
curl: (56) CONNECT tunnel failed, response 407. - Requests:
ProxyError ... Tunnel connection failed: 407 Proxy Authentication Required. - Scrapy:
TunnelError: Could not open CONNECT tunnel with proxy ... [{'status': 407, 'reason': b'Proxy Authentication Required'}]. - Puppeteer without
page.authenticate():ERR_INVALID_AUTH_CREDENTIALS. - Puppeteer with a wrong password: no exception at all.
page.goto()resolves with status 407 and Chrome's error page, so always checkresponse.status(). - Playwright with a wrong password:
ERR_HTTP_RESPONSE_CODE_FAILURE.
A warning for when you ask for help: curl -v prints the Proxy-Authorization header, which is just your username and password in base64. Anyone can decode it. Delete that line before you paste verbose output into a ticket or a forum.
403 Forbidden
Look at %{http_connect} first.
If the proxy returned the 403, it understood the request and refuses to carry it. The destination may be blocked by the provider's usage policy, or the plan may not include that product. curl shows CONNECT tunnel failed, response 403 and Requests shows Tunnel connection failed: 403 Forbidden. Check the plan, and if the destination is legitimate, ask support.
If the website returned the 403, which is far more common, the site decided the request does not look like a real visitor. The IP is only one of the signals. Others weigh as much or more:
- A default user agent.
curl/8.19.0andpython-requests/2.34.2are blocked on sight by many sites. - Missing or inconsistent headers, such as no
Accept-Language, or a Chrome user agent with headers Chrome would never send. - TLS fingerprints that do not match the claimed browser.
- Request pace no human could produce.
- An IP type the site distrusts. Datacenter ranges are blocked by strict targets where residential, ISP or mobile exits pass.
Fix the headers and the pace before you switch pools. Switching to a more expensive IP type rarely helps if the request itself is what gives you away. The ten proxy mistakes cover these in detail.
429 Too Many Requests
The website is rate limiting you. Many sites include a Retry-After header that says how many seconds to wait. Respect it: retrying immediately usually extends the block.
What helps:
- Slow down, and add jitter so requests do not arrive on a fixed beat.
- Spread the load across more exits. With rotating sessions each new connection can leave through a different IP.
- Do not hammer one sticky session. A sticky IP that sends hundreds of requests a minute gets limited fast.
- Use retries with exponential backoff. In Python, urllib3's
RetryhonoursRetry-Afteron 429 and 503 by default; the Python Requests guide has a ready-made setup.
502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout
These three come from a server acting as a gateway: either the proxy or a CDN in front of the website. On HTTPS, %{http_connect} tells you which.
From the proxy:
- 502 means the proxy got no valid answer from the next hop. On residential and mobile pools, an individual exit going offline mid-request is normal, because those exits are real home and phone connections. Retry. On a rotating session the retry leaves through a different exit; on a sticky session a dead exit stays dead, so switch to a new session id.
- 504 means the next hop did not answer in time. The target is slow, or the exit is. Retry, and give slow targets a longer read timeout.
- 503 means the proxy cannot serve the request right now. Some providers also return 502 or 503 when no exit matches very narrow targeting, such as a small city at a quiet hour. Widen the targeting to check.
In browsers, a proxy that refuses the tunnel with any of these codes, or with a 403, shows up as net::ERR_TUNNEL_CONNECTION_FAILED.
From the website, a 502, 503 or 504 means its own servers or CDN are struggling. Some anti-bot services also answer with a 403 or a 503 challenge page instead of the content. Read the body, not just the code.
451 Unavailable For Legal Reasons
Rare, but worth knowing: the site blocks this content in the country your exit is in. Pick an exit in another country.
Connection errors with no status code
Some failures happen before any HTTP status exists. These are almost always configuration mistakes, and the error text points at the cause.
Wrong host or port, or nothing listening there. curl prints curl: (7) Failed to connect to ... and ends with Could not connect to server. Requests raises ProxyError ... Failed to establish a new connection. Chrome shows net::ERR_PROXY_CONNECTION_FAILED. Check the host and port on your plan page, and that your network allows outbound traffic on that port.
A typo in the proxy hostname. curl: curl: (5) Could not resolve proxy: <host>.
SOCKS5 on the HTTP port. An HTTP proxy usually answers the SOCKS5 greeting with an HTTP error, which the client cannot read. curl: curl: (97) Received invalid version in initial SOCKS5 response. Requests: SOCKS5 proxy server sent invalid data. Each product has separate HTTP and SOCKS5 ports.
HTTP on the SOCKS5 port. curl typically reports curl: (56) Proxy CONNECT aborted and Requests ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')).
The https scheme on a plain HTTP proxy. With https:// in front of the proxy address, the client tries to speak TLS to a port that does not. curl fails with exit code 35 (SSL connect error); the message depends on the TLS library. Requests explains it outright: Your proxy appears to only use HTTP and not HTTPS, try changing your proxy URL to be HTTP. The scheme describes how you talk to the proxy, not the site, so it should be http:// even for HTTPS sites.
Wrong SOCKS5 credentials. curl: curl: (97) User was rejected by the SOCKS5 server (1 1). Requests: SOCKS5 authentication failed.
SOCKS5 with a password in Chrome. Chrome cannot log in to SOCKS5 proxies. Puppeteer fails with net::ERR_SOCKS_CONNECTION_FAILED, and Playwright refuses to launch: Browser does not support socks5 proxy authentication. Use the HTTP port.
Credentials inside Chrome's proxy flag. A username and password in --proxy-server give net::ERR_NO_SUPPORTED_PROXIES. Chrome wants the address only; Puppeteer passes credentials with page.authenticate().
Timeouts. curl: curl: (28) Operation timed out after ... milliseconds with 0 bytes received. Requests: ReadTimeout or ConnectTimeout. Playwright: TimeoutError: Page.goto: Timeout 30000ms exceeded. Residential exits add latency, so allow a few seconds more than you would without a proxy, and retry instead of waiting forever.
SOCKS support missing in Python. InvalidSchema: Missing dependencies for SOCKS support. Install it with pip install "requests[socks]".
SOCKS5 reply codes
SOCKS5 does not use HTTP status codes. After the login step, the proxy answers a connect request with a one-byte reply code defined in RFC 1928:
0x00: succeeded.0x01: general server failure.0x02: connection not allowed by the server's rules.0x03: network unreachable.0x04: host unreachable.0x05: connection refused by the destination.0x06: TTL expired.0x07: command not supported, for example UDP or BIND on a proxy that only relays TCP connections.0x08: address type not supported, for example an IPv6 destination on an IPv4-only route.
The login step itself is RFC 1929: the server answers with a status byte where 0x00 means success and anything else means rejected. That is what curl's (1 1) shows: version 1, status 1.
A debugging order that works
- Run one request with curl against
https://api.ipify.org. If you get an IP back that is not yours, the proxy works and the problem is in your client or at the target. - Check host, port and scheme together. HTTP port with
http://, SOCKS5 port withsocks5h://. - Copy the credentials fresh, then percent-encode them or use
-U. - Check the plan still has traffic and has not expired.
- Split proxy errors from site errors with
%{http_connect}. - For site errors, fix headers, pace and session handling before changing pools.
- Still stuck? Send support the exact command and the full error, minus the
Proxy-Authorizationline.
The 60-second proxy test walks through steps 1 and 2 in more detail.
FAQ
What does error 407 mean on a proxy? The proxy requires authentication and did not accept what it received. Check the username, the password, and whether the password needs percent-encoding.
Is a 403 the proxy's fault? Usually not. On an HTTPS request, if %{http_connect} is 200, the 403 came from the website.
Why do I get random 502 errors on residential proxies? Residential exits are real home connections that come and go. An occasional 502 on a single request is normal; retry it. A steady stream of them is worth a support ticket.
Why does my client say "connection refused"? Nothing accepted the connection on that host and port. You are most likely using the wrong port for the product or protocol.
Testing without code
The NyxonProxies dashboard has a proxy tester on the Generate page: paste any proxy string, click Test, and it reports the exit IP, location and latency, or the error. If you do not have an account yet, sign up, link Discord under Freebies and you get 250MB of Residential Budget traffic free to run these checks on real targets.