Skip to content

How to Fix 403 Forbidden Errors When Using a Proxy

A 403 through a proxy can come from the site or from the proxy. One command separates them, and the next step is different for each.

Billal AinaouiJuly 3, 2026Updated October 13, 20268 min read

How to Fix 403 Forbidden Errors When Using a Proxy

You point curl at a site through your proxy, wait for the HTML, and get one line back: 403 Forbidden. No page. No redirect. No login form. The proxy connected, the server answered, and the answer was no.

Nothing broke. The TCP handshake happened, your proxy relayed the bytes, and something read your request and refused it. That something is either the site or the proxy itself, and the next step depends on which.

What causes a 403 Forbidden error through a proxy?

A 403 means a server received your request and refused it. RFC 9110 puts it in one sentence: "The 403 (Forbidden) status code indicates that the server understood the request but refuses to fulfill it." Usually that server is the site, applying its own rules: a login you lack, a rule about clients, a limit on addresses or countries, or a firewall service in front of it. Sometimes it is the proxy, refusing on its own policy. The next section separates the two in one command.

First: who sent it?

One thing has to be settled before any fix, because the same status code comes from two different places. The site can refuse you, and the proxy can refuse you, on its own policy, before the site ever sees the request. RFC 9110 says the server understood the request and refused it, and a proxy is a server.

We built both cases on September 16, 2026, with a stub proxy and a stub site on our own machine, and asked curl for a plain page and an https page through each:

What we asked forWho refusedWhat came back
plain pagethe proxyexit 0, 403, with Via: 1.1 stub-proxy and Proxy-Agent headers and the proxy's own body
https pagethe proxyexit 56, CONNECT tunnel failed, response 403, the site never reached
plain pagethe siteexit 0, 403, with the site's Server header and no Via
https pagethe siteexit 0, HTTP/1.1 200 Connection established first, then the site's 403

That gives two checks, and both take one command:

# Ask for an https page. The answer is unambiguous.
curl -i --proxy http://203.0.113.7:8080 https://example.com/

# CONNECT tunnel failed, response 403  ->  the proxy refused. The site is not involved.
# 200 Connection established, then 403  ->  the proxy did its job and the site refused.
# Ask for a plain page and read the headers.
curl -i --proxy http://203.0.113.7:8080 http://example.com/

# A Via or Proxy-Agent header on the 403  ->  the proxy answered.
# The site's own Server header and no Via  ->  the site answered.

The Via header is what makes the second check work: it is added by proxies on the way through, so a refusal that carries one came from a machine in the middle. Not every proxy sets it, which is why the https test is the reliable one.

There is a third sender worth knowing. A protection layer in front of the site can refuse before the site does, and Cloudflare marks its own challenge responses with a cf-mitigated header, documented here.

And if a script is doing the asking, make it notice. In our run the proxy refusal left curl at exit code 0, with the proxy's page as the body. A job that checks only the exit code recorded a success for a page it never fetched. Adding --fail turned the same request into exit 22 with the status in the message.

Who refused, and what to do next

The proxy refused

  • CONNECT tunnel failed

    or a Via or Proxy-Agent header

  • Use port 443

    Squid denies other CONNECT ports

  • Check the proxy's rules

    allowed addresses, blocked sites

  • Ask whoever runs it

    an office proxy is their call

The site refused

  • Tunnel open, then 403

    or a cf-mitigated header

  • Read the reason

    the body may say why

  • Fix your own access

    login, token, API key

  • Ask the site or use its API

    its rules stay the same

Source: RFC 9110, Squid's default configuration, Cloudflare's documentation and our measurement of September 16, 2026 · hproxy.comProxy.

If the proxy refused you

A proxy refuses for its own reasons, and its configuration says which. Squid is a common example. Its default configuration carries the line http_access deny CONNECT !SSL_ports, under the comment "Deny CONNECT to other than secure SSL ports", and Squid answers a denied request with 403 Forbidden unless its administrator sets another code. So an https site on an unusual port, such as https://example.com:8443, can be refused by the proxy while the same site on 443 goes through. Use port 443 where the site offers it.

Other refusals come from the proxy's own lists. An office or school proxy can block sites by name or category, and that rule is its administrator's to change. A paid proxy that admits only listed client addresses can refuse yours after your connection changes; the allowed addresses sit in your plan's settings. Read the proxy's own error page, too: it is the body that came back with the Via or Proxy-Agent header, and it often names the rule. Chrome shows the same refusal as ERR_TUNNEL_CONNECTION_FAILED, and a proxy that wants a login answers 407 instead, which our 407 guide covers.

If the site refused you

The tunnel opened, or no Via came back, and the site said no. Work through these in order.

  1. Read the answer. RFC 9110 allows a server "that wishes to make public why the request has been forbidden" to "describe that reason in" the response. Read the body and the headers. A cf-mitigated: challenge header means Cloudflare's challenge answered, as its documentation describes. A login page, a message or an error code from the site tells you more than the status.
  2. Check your own access. Some 403s mean you lack a login cookie, a token or an API key, and then the request fails from any address. Test the same request from your own connection with the right credentials. RFC 9110 is direct about retries: the client "SHOULD NOT automatically repeat the request with the same" credentials, though it "MAY repeat the request with new or different" ones. It adds that a refusal can be "unrelated to the credentials."
  3. Say who you are. Some sites refuse anonymous scripts. Wikimedia states its rule plainly: "On Wikimedia wikis, if you don't supply a User-Agent header, or you supply an empty or generic one, your request will fail with an HTTP 403 error." Its policy asks for "an informative User-Agent string with contact information", and gives this example: User-Agent: CoolBot/0.0 (https://example.org/coolbot/; coolbot@example.org) generic-library/0.0. Name your tool and a way to reach you.
  4. Use the site's own route. Many sites offer an API or a data feed, and every site publishes its rules for automated clients in its robots.txt and its terms. If the site answers with 429 instead, it is asking you to slow down; our 429 guide covers waiting and retrying. When none of that fits, ask the site's owner.
  5. If the site is yours, allow your own traffic. Testing your own site through proxies from other countries can trip your own firewall. Cloudflare documents the fix for its customers: "Another common use of IP Access rules is to allow services that regularly access your site, such as APIs, crawlers, and payment providers." IP Access rules can name an address, a range, a network or a country, and "IP Access rules are available to all customers." Add the addresses you test from.

This page leaves out disguising a script as a browser, matching TLS fingerprints, rotating addresses past a refusal and moving to another country to pass a geographic block. Each of them works around a decision the site made.

When the 403 is not about the proxy at all

One more check, because chasing the proxy when the proxy is fine wastes hours. If the same request with the right credentials also fails from your own connection, the block is about authentication or permissions, and no proxy change touches it. If it works from your connection and fails through the proxy, the site treats the proxy's address differently, which is the site's rule, as in step 5 above when the site is yours.

Check what your proxy sends

A transparent proxy passes your real IP to the site in headers like X-Forwarded-For or Via. X-Forwarded-For is the de-facto standard MDN documents for carrying a client's originating IP through a proxy chain, and Via is defined in RFC 9110 section 7.6.3 to record the intermediaries a message passed through. An elite (high anonymity) proxy sends neither. Run your proxy through our proxy checker, which shows the headers the destination receives, so you know what the site sees before you read its answer.

Where HProxy fits

A proxy changes the address a request comes from, and a site's rules stay the same. For checking your own site, ads or prices from other countries, our residential proxies start at $0.44 per GB; allow their addresses in your own firewall as in step 5. Our proxy checker tells you whether an exit is elite before you route a request through it.

What we could not find out

  • Which sites refuse proxy or hosting addresses as such. Sites set those rules one by one, and few publish them.
  • How Cloudflare scores a request before it challenges. Its documents describe the tools a site owner sets, such as IP Access rules, and the cf-mitigated header on a challenge.

Sources

Frequently asked questions

Does a 403 error mean my proxy is broken?

Usually not, and not always. Most of the time the connection succeeded and the site refused your request on purpose. But a proxy can refuse on its own policy too. We measured both on September 16, 2026: a proxy refusal of an https page gives curl exit 56 with CONNECT tunnel failed, response 403, and the site is never reached, while a site refusal shows the tunnel being established first. On a plain page, a Via or Proxy-Agent header on the response is the proxy's fingerprint.

Why do I get a 403 with a proxy but not from my home connection?

Because the site, or a service in front of it, treats the proxy's address differently from yours. Sites set their own rules, and services such as Cloudflare let a site owner allow, block or challenge traffic by IP address, network or country. That is the site's decision. If the site is yours, allow the addresses you test from; if it belongs to someone else, use its API or ask its owner. Check first that the 403 came from the site and not from the proxy.

Will rotating IPs fix a 403 error?

Rotating addresses to get past a refusal works around the site's decision, and this page gives no steps for it. RFC 9110 defines a 403 as a refusal the server made after understanding the request, and it says a client should not automatically repeat the request with the same credentials. If the proxy refused, change the port or the proxy's settings. If the site refused, fix your credentials, read the reason in the response, or ask the site's owner.

What request headers help avoid a 403?

Honest ones. Some sites refuse requests with no User-Agent or a generic one. Wikimedia's wikis answer those with a 403 and ask scripts for an informative User-Agent with contact information, such as CoolBot/0.0 (https://example.org/coolbot/; coolbot@example.org). Name your tool and a way to reach you. Dressing a script up as a browser hides who is asking, and we give no steps for it.

How do I know if my proxy is elite or transparent?

A transparent proxy leaks your real IP in headers like X-Forwarded-For or Via, so the target can tell you are proxying. An elite proxy sends none of those. Run the proxy through a checker that echoes the headers the destination receives, and if your real IP shows up, the proxy is not elite.

Why do real browser headers fix some 403s but not others?

Because one status code covers different rules. A simple rule may refuse requests without a User-Agent, and an informative one satisfies it, as on Wikimedia's wikis. A service in front of the site, such as Cloudflare, weighs more than headers and marks its challenge responses with a cf-mitigated header. Both are the site's decisions. This page shows how to tell them apart and gives no way past them.

Get proxies that are alive right now

Our free proxy list re-checks every exit every few minutes across 100+ countries, with a live last-checked time, so you copy IPs that worked moments ago, not a stale text dump. When the location has to survive a real check, the paid network holds up.

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