The short answer to SOCKS5 vs HTTP proxy: for web traffic, use an HTTP proxy. HTTPS is carried inside an opaque CONNECT tunnel either way, every HTTP client and browser supports HTTP proxies with credentials, and setting up a connection takes fewer round trips. Choose SOCKS5 when you need to carry something other than HTTP, when your tool only speaks SOCKS, or when the application must reach the proxy with no HTTP semantics in between, and when you do, make sure hostnames are resolved at the proxy (socks5h://), not on your machine.
The rest of this guide explains why, with the protocol details that decide the edge cases: DNS resolution, UDP, the actual performance difference, and which clients support what.
How an HTTP proxy works
An HTTP proxy speaks HTTP to your client and handles two kinds of request, both defined in RFC 9110 and its companion RFC 9112.
Plain HTTP targets use absolute-form requests. Instead of sending GET /products HTTP/1.1 to the origin, the client sends the full URL to the proxy, which opens its own connection to the target and forwards the request:
GET http://example.com/products?page=2 HTTP/1.1
Host: example.com
Proxy-Authorization: Basic VVNFUk5BTUU6UEFTU1dPUkQ=
Because the proxy parses this request, it can read it, cache it and modify it, for example by adding a Via header. It also sees the full URL and response.
HTTPS targets use a CONNECT tunnel. The client asks the proxy to open a raw TCP connection to a host and port:
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
Proxy-Authorization: Basic VVNFUk5BTUU6UEFTU1dPUkQ=
HTTP/1.1 200 Connection established
After the 200, the proxy is a byte relay. The client performs its TLS handshake with the target through the tunnel, and from then on the proxy sees only encrypted bytes and the hostname and port it was asked to connect to. It cannot read the path, headers or body, and it cannot alter the response. This is why most of the security and privacy arguments for SOCKS5 over HTTP do not apply to HTTPS traffic: once the tunnel is open, the two protocols do the same thing.
Credentials travel in the Proxy-Authorization header, usually as HTTP Basic, which is base64 and not encryption. The gateway answers bad credentials with 407 Proxy Authentication Required.
How a SOCKS5 proxy works
SOCKS5, defined in RFC 1928, works one layer lower. It knows nothing about HTTP; it negotiates a connection to a host and port and then relays bytes. With username and password authentication from RFC 1929, a connection starts like this:
client -> proxy 05 01 02 version 5, offers method 0x02 (username/password)
proxy -> client 05 02 selects username/password
client -> proxy 01 <len> USERNAME <len> PASSWORD
proxy -> client 01 00 authentication succeeded
client -> proxy 05 01 00 03 0b "example.com" 01 bb
CONNECT, address type 0x03 (domain name), port 443
proxy -> client 05 00 00 01 <bound address> <bound port>
succeeded; relay begins
Three details in that exchange matter in practice:
- The address type in the
CONNECTrequest can be an IPv4 address (0x01), a domain name (0x03) or an IPv6 address (0x04). Which one the client sends decides where DNS is resolved, covered in the next section. - The password crosses in cleartext. RFC 1929 says so explicitly. SOCKS5 is no more private than HTTP Basic on the client-to-proxy hop.
- Besides
CONNECT, the protocol definesBIND(for protocols such as active-mode FTP that need an inbound connection) andUDP ASSOCIATE. Commercial gateways rarely implement either.
Since SOCKS5 does not parse the traffic it carries, it works for any TCP protocol: HTTP, HTTPS, database wire protocols, SSH, or your own. For HTTPS, the result is the same opaque relay a CONNECT tunnel gives you.
Where DNS is resolved: socks5 vs socks5h
With an HTTP proxy, DNS is straightforward: the client sends a hostname in the CONNECT line or the absolute URL, and the proxy resolves it. With SOCKS5, the client chooses. It can resolve the hostname itself and send an IP address, or send the domain name for the proxy to resolve.
The difference is not academic:
- Local resolution leaks the lookup. Your own resolver, and whoever operates it, sees every hostname you visit.
- Local resolution can pick the wrong server. Large sites and CDNs answer DNS with an address close to the resolver. Resolve locally in Frankfurt while exiting in Tokyo and you may connect to a European edge node from a Japanese address, which produces the wrong regional content or an inconsistency a bot-management system can flag. This matters for any geo-dependent work; see geo-targeting proxies for how to verify the exit country.
- Split-horizon names fail. Hostnames that only resolve inside the proxy's network cannot be resolved on your side at all.
Many tools encode the choice in the URL scheme: socks5:// means resolve locally, socks5h:// means send the hostname to the proxy. We checked what each client actually sends by logging the CONNECT requests arriving at a local SOCKS5 proxy:
| Client | socks5:// |
socks5h:// |
|---|---|---|
| curl | IP address (local DNS) | Hostname (DNS at proxy) |
Python Requests with requests[socks] |
IP address | Hostname |
httpx 0.28 with httpx[socks] |
Hostname | Hostname |
Node.js socks-proxy-agent |
IP address | Hostname |
undici Socks5ProxyAgent |
Hostname | Not applicable |
Chromium (--proxy-server=socks5://…) |
Hostname | Not applicable |
The safe habit is to write socks5h:// wherever the client accepts it. In curl, --socks5-hostname is the flag equivalent.
UDP ASSOCIATE and what actually supports it
SOCKS5 is often described as supporting UDP, and the protocol does: UDP ASSOCIATE asks the proxy to open a UDP relay, the client wraps each datagram in a small header carrying the destination address, and the association lives as long as the TCP control connection that created it.
In practice, two things have to be true for proxied UDP to work, and they rarely are:
- The gateway must implement it. Most commercial proxy gateways, whether residential, mobile, ISP or datacenter, support only TCP
CONNECT. Relaying UDP from peer devices behind consumer NAT is considerably harder than relaying TCP, and many networks do not offer it at all. - The client must use it. curl, Python Requests, httpx, the Node.js agents and the major browsers send TCP only through a SOCKS5 proxy. HTTP/3, which runs over QUIC on UDP, is therefore not proxied; clients fall back to HTTP/2 or HTTP/1.1 over TCP.
If a workload genuinely needs UDP (DNS over the proxy, QUIC, real-time media, game traffic), ask the vendor for written confirmation that its gateway supports UDP ASSOCIATE on the line you are buying, then test it with your own client before you commit. Do not infer UDP support from the word "SOCKS5" on a product page.
Is SOCKS5 faster than an HTTP proxy?
In most SOCKS5 vs HTTP proxy comparisons, the claim is that SOCKS5 is faster because it is "lower level" and has less overhead. Once a connection is established, both protocols relay bytes with no per-packet framing, so throughput is the same. The difference is in connection setup, and it favors HTTP.
Count the round trips to the proxy before the target's TLS handshake can begin:
- HTTP proxy, HTTPS target: one. The
CONNECTrequest carriesProxy-Authorization, and the200comes back. - SOCKS5 without authentication: two. Method negotiation, then
CONNECT. - SOCKS5 with username and password: three. Method negotiation, the RFC 1929 sub-negotiation, then
CONNECT.
We measured this in a lab: curl to a local proxy through a relay adding 100 ms of round-trip latency, fetching an HTTPS page over TLS 1.3. The TLS handshake completed after about 210 ms through the HTTP proxy and about 410 ms through SOCKS5 with credentials, consistently across runs. That is exactly two extra round trips.
On a fast network path to the gateway, a round trip costs a few milliseconds and the difference disappears in the target's response time. On a long path, or with a client that opens a fresh connection per request, it adds up. Either way, connection reuse matters far more than the protocol: a keep-alive session that sends many requests through one tunnel pays the setup cost once. The same applies to rotation. On a rotating endpoint, a new connection is often what gets you a new exit, so reuse and rotation are a trade-off; rotating vs sticky proxies covers it.
The other performance myth runs the opposite way: that an HTTP proxy slows HTTPS by inspecting it. A CONNECT tunnel cannot be inspected without the client trusting a certificate the proxy controls, which a normal commercial gateway does not ask you to do.
Client support matrix
The protocols are well supported in libraries and less so in browsers, mainly because browsers have no way to send SOCKS5 credentials.
| Client | HTTP proxy with credentials | SOCKS5 | SOCKS5 with credentials |
|---|---|---|---|
| curl | Yes, -x http://USERNAME:PASSWORD@host:port |
Yes | Yes |
| Python Requests | Yes | With requests[socks] |
Yes |
| httpx | Yes | With httpx[socks] |
Yes |
Node.js http/https, axios |
Yes, via https-proxy-agent |
Via socks-proxy-agent |
Yes |
Node.js fetch (undici) |
Yes, ProxyAgent or EnvHttpProxyAgent |
Experimental Socks5ProxyAgent |
Yes |
| Chrome and Chromium | Yes, credentials via the auth prompt or automation, not in --proxy-server |
Yes | No |
| Firefox | Yes, credentials via the auth prompt | Yes | Not in its proxy settings |
| Playwright | Yes, username and password |
Yes | No, launch fails |
The Playwright row is worth spelling out. Passing a socks5:// server together with a username or password throws Browser does not support socks5 proxy authentication before the browser starts; we saw this with both Chromium and Firefox. Puppeteer has the same limit, because page.authenticate answers HTTP authentication challenges only. Browser automation over SOCKS5 therefore means authenticating by source address instead; IP allowlist vs username and password covers that trade-off, and the Playwright proxy guide shows both setups.
For libraries, the scheme is the only change. In Python Requests:
import os
import requests
proxy_url = os.environ["SOCKS_PROXY_URL"] # socks5h://USERNAME:[email protected]:PORT
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.get("https://api.ipify.org", proxies=proxies, timeout=30)
print(response.text)
And in curl, the same request over either protocol:
curl -x "$PROXY_URL" https://api.ipify.org
curl -x "$SOCKS_PROXY_URL" https://api.ipify.org
SOCKS5 vs HTTP proxy compared
| HTTP proxy | SOCKS5 proxy | |
|---|---|---|
| Specification | RFC 9110, RFC 9112 | RFC 1928, RFC 1929 for credentials |
| Traffic carried | HTTP; any TCP via CONNECT where the gateway allows the port |
Any TCP; UDP only if both sides implement UDP ASSOCIATE |
| Sees plain-HTTP content | Yes, and can modify it | No, relays bytes |
| Sees HTTPS content | No, CONNECT tunnel |
No |
| DNS resolution | At the proxy | Client's choice: socks5h:// at the proxy, socks5:// locally in most tools |
| Round trips to open a tunnel | One | Two, or three with credentials |
| Credentials on the wire | Base64 in a header, readable | Cleartext, readable |
| Browser support with credentials | Universal | None in Chromium, Firefox settings or Playwright |
| Typical failure signal | 407, or 5xx on CONNECT |
SOCKS reply code, surfaced as a connection error |
The last row affects operations more than people expect. An HTTP proxy's 407 or 502 is a readable status in your logs; a SOCKS5 failure usually reaches your code as a generic connection exception with the reply code buried in its message. If you classify errors to tell proxy failures from target failures, as described in diagnosing proxy 429 and 403 errors, HTTP gives you cleaner data.
Which should you use?
The SOCKS5 vs HTTP proxy decision reduces to a short rule. Apply these in order and stop at the first that matches:
- The traffic is not HTTP or HTTPS (a database, SSH, a custom TCP protocol): use SOCKS5 with
socks5h://, subject to the provider's acceptable use policy for that protocol. - The traffic needs UDP: neither protocol will work unless the vendor confirms
UDP ASSOCIATEin writing and your test passes. Plan on that not being available. - A browser needs credentials: use the HTTP proxy. Browsers cannot send SOCKS5 credentials.
- The tool only speaks SOCKS5: use SOCKS5, with
socks5h://or its equivalent. - Everything else, which is most web data work: use the HTTP proxy. HTTPS is equally opaque either way, setup is faster, errors are clearer and every client supports it.
Whichever you choose, the client-to-proxy hop is not encrypted by either protocol. If that hop crosses a network you do not trust, prefer IP allowlisting to credentials, or a gateway that accepts TLS on the proxy connection itself.
Using either protocol with ProxyForge
Every ProxyForge line, residential, mobile, ISP and datacenter, accepts HTTP, HTTPS and SOCKS5, with either username and password or an IP allowlist. The dashboard issues the gateway host, port and credentials for your account, so switching protocols is a change of scheme in the connection string, http://USERNAME:[email protected]:PORT or its socks5h:// equivalent, not a change of plan.
If you are unsure which fits a particular workload, or need to confirm how a non-HTTP protocol would be handled, a named engineer can check it with you before you commit; the contact page is the quickest route.