Pick SOCKS5, and let the proxy resolve the hostname. That is socks5h:// in curl and Python, and the default in Firefox and Chrome. SOCKS4 is the right choice only when a tool or an endpoint speaks nothing newer. Then you accept three limits: IPv4 targets only, no password, and your own machine looks up every name. SOCKS4a fixes the lookup and nothing else. Speed is not one of the differences. The handshake differs by a few bytes, and every proxy list column that says "SOCKS4" or "SOCKS5" is a label, not a capability.
We run a proxy network, so we read the four protocol documents and then measured. We wrote a small SOCKS server that prints what each request puts on the wire, and ran curl through it six ways. We also probed 80 entries from our free proxy list, 50 distinct public proxies, for IPv6, UDP and authentication. Every number below carries its source and its date.
What actually changes between SOCKS4 and SOCKS5?
Four things change, and one thing does not. SOCKS5 adds a negotiated authentication step, a hostname address type, IPv6 addresses, and a UDP relay command. RFC 1928 (IETF, March 1996) says so in one sentence. The new protocol "extends the SOCKS Version 4 model to include UDP", adds "provisions for generalized strong authentication schemes", and covers "domain-name and V6 IP addresses". What does not change is encryption. Neither version encrypts a byte of the relayed traffic.
What SOCKS4 puts on the wire
SOCKS4 is tiny. A client sends one request packet. The SOCKS4 protocol document (Ying-Da Lee, NEC, undated, cited by RFC 1928) lays out its fields exactly:
- VN, 1 byte: the version, "should be 4".
- CD, 1 byte: the command, "should be 1 for CONNECT request", or 2 for BIND.
- DSTPORT, 2 bytes: the destination port.
- DSTIP, 4 bytes: the destination IP address.
- USERID, variable length: an identifying string.
- NULL, 1 byte: "a byte of all zero bits" that ends the userid.
The proxy answers with its own small packet: a VN byte that "should be 0", then a result code. The codes are 90 for "request granted" and 91 for "request rejected or failed". Code 92 means rejected "because SOCKS server cannot connect to identd on the client". Code 93 means "the client program and identd report different user-ids". Those last two show the era. Access control in SOCKS4 rests on "source IP address, destination IP address, destination port number, the userid", and on identd. That is RFC 1413, a protocol for asking a remote machine who owns a connection. There is no password field anywhere.
Read the layout again and the three walls of SOCKS4 are already there. DSTIP is 4 bytes, so the destination is IPv4 only. The commands are CONNECT and BIND, both TCP, so there is no UDP. And the destination is sent as an address, not a name, so the client has to resolve the hostname before it sends the request. That lookup goes to the local resolver. Even with the traffic proxied, the machine has told its own DNS server every domain it is about to visit.
What SOCKS4a bolted on
SOCKS4a is a patch for exactly that lookup, written for "hosts which are not capable of resolving all domain names". It reuses the SOCKS4 packet with one trick. The SOCKS4a document tells the client to set "the first three bytes of DSTIP to NULL and the last byte to a non-zero value". That is the reserved form 0.0.0.x, and the impossible address is a flag. After the userid null byte, "the client must send the destination domain name and terminate it with another NULL byte". A server that sees 0.0.0.x reads the appended name and resolves it.
That is the ancestor of every remote DNS setting you use today. SOCKS4a is strictly this bolt-on: still IPv4 for the resolved address, still TCP only, still no password. In our wire test below, curl --socks4a sends exactly DSTIP=0.0.0.1 followed by example.com.
What SOCKS5 rebuilt
SOCKS5, defined in RFC 1928, is a negotiated protocol, not SOCKS4 with a higher number. The client greets the proxy with a version byte (0x05) and a list of authentication methods it supports. The proxy picks one. The defined values are 0x00 "no authentication required", 0x02 username and password from RFC 1929, and 0x01 GSS-API from RFC 1961. A reply of 0xFF means nothing offered is acceptable, and the client must close. Only then does the client send its request.
That structure carries every SOCKS5 upgrade:
- Authentication. The method negotiation is how a commercial SOCKS5 endpoint requires a login before it relays anything. RFC 1928 says compliant implementations "MUST support GSSAPI and SHOULD support USERNAME/PASSWORD". The IANA method registry adds numbers for CHAP, challenge-response, SSL, NDS and a JSON block, and reserves
0x80to0xFEfor private methods. - Commands. The request command byte is
0x01CONNECT,0x02BIND, or0x03UDP ASSOCIATE. The third one is new. A SOCKS5 server can relay UDP datagrams, which SOCKS4 cannot express at all. - Address types. An
ATYPbyte says how to read the destination.0x01is a 4-byte IPv4 address,0x03a domain name with a length prefix and "no terminating NUL octet",0x04a 16-byte IPv6 address. IPv6 and native hostnames both arrive here. The domain type makes remote DNS a first-class feature instead of the0.0.0.xhack. - Reply codes. A server that will not do something says so.
0x07"Command not supported" and0x08"Address type not supported" are the two answers you will meet most. Our probe met both.
Your client
sends a domain name
SOCKS5 proxy
resolves DNS
Target host
SOCKS4 needed an IP
We walk through the full handshake in what is a SOCKS5 proxy. The short version: with SOCKS5 you can hand the proxy a hostname and keep your DNS off your local network. SOCKS4 could never do that, and SOCKS4a only faked it.
The three side by side, with the section behind each cell
| SOCKS4 | SOCKS4a | SOCKS5 | Where it says so | |
|---|---|---|---|---|
| Version byte | 0x04 | 0x04 | 0x05 | SOCKS4 doc; RFC 1928 s.3 |
| Transport | TCP | TCP | TCP and UDP | SOCKS4 doc; RFC 1928 s.2 |
| Commands | CONNECT, BIND | CONNECT, BIND | CONNECT, BIND, UDP ASSOCIATE | SOCKS4 doc; RFC 1928 s.4 |
| Destination address | IPv4, 4 bytes | IPv4, or hostname after a 0.0.0.x marker | IPv4, hostname, or IPv6 (16 bytes) | SOCKS4 doc; SOCKS4a doc; RFC 1928 s.5 |
| Who resolves DNS | Your client | The proxy | Your client or the proxy, per request | SOCKS4a doc; RFC 1928 s.5 |
| Authentication | userid string, identd | userid string, identd | Negotiated: none, username/password, GSS-API, others | SOCKS4 doc; RFC 1928 s.3; IANA registry |
| Password on the wire | none exists | none exists | cleartext with method 0x02 | RFC 1929 s.3 |
| UDP relaying | No | No | Yes, UDP ASSOCIATE | RFC 1928 s.4 and s.7 |
| IPv6 | No | No | Yes, ATYP 0x04 | RFC 1928 s.5 |
| Encryption of traffic | None | None | None, unless the GSS-API method is used | RFC 1928 s.4; RFC 1961 s.1 |
| Registered port | 1080 | 1080 | 1080, TCP and UDP | IANA port registry |
The pattern is clear. SOCKS4a fixed one SOCKS4 gap, hostnames, and SOCKS5 fixed all of them and added UDP and IPv6 on top. The one row that does not improve is encryption. If your connection is private, that is TLS doing the work, whatever SOCKS version carried it.
Who resolves the hostname, and why it matters
This is the difference that costs people privacy, and it is invisible unless you look at the wire. We looked. We wrote a 60-line SOCKS4, SOCKS4a and SOCKS5 server on 127.0.0.1:1080. It prints every field it receives, then relays to the real target. Then we ran curl 8.16.0 on Windows 11 through it six ways against https://example.com/ on 2 September 2026.

| curl command | What arrived at the proxy | Who resolved the name |
|---|---|---|
curl --socks4 127.0.0.1:1080 … | VN=4 CD=1 DSTIP=104.20.23.154 USERID="" | curl |
curl --socks4a 127.0.0.1:1080 … | VN=4 CD=1 DSTIP=0.0.0.1 HOSTNAME="example.com" | the proxy |
curl -4 --socks5 127.0.0.1:1080 … | ATYP=0x01 DST.ADDR=104.20.23.154 | curl |
curl --socks5-hostname 127.0.0.1:1080 … | ATYP=0x03 DST.ADDR=example.com | the proxy |
curl -x socks5://127.0.0.1:1080 … | ATYP=0x04 DST.ADDR=2606:4700:10::ac42:93f3 | curl |
curl -x socks5h://127.0.0.1:1080 … | ATYP=0x03 DST.ADDR=example.com | the proxy |
All six returned HTTP 200 through our server. The fifth row deserves a second look. On a dual-stack machine, plain socks5:// resolves locally and puts an IPv6 address into the request. A public proxy without an IPv6 route then answers 0x08 or 0x03, and the request fails for a reason nobody typed. Through a public SOCKS5 proxy from our list, the same command failed with "cannot complete SOCKS5 connection (8)" while --socks5-hostname returned 200. Either add -4 or, better, let the proxy resolve.
The curl manual (curl 8.16.0, released 10 September 2025) states the rule in plain words. --socks4 "makes curl resolve the hostname and pass the address on to the proxy". --socks4a "asks the proxy to resolve the hostname". --socks5 resolves "the hostname locally". --socks5-hostname lets "the proxy resolve the hostname". The socks5h:// scheme is the same thing spelled as a URL.
We then proved where the lookup happens, using a public SOCKS5 proxy from our list and the Windows resolver cache. Flush the cache, run curl -4 --socks5 to https://example.net/, and ipconfig /displaydns lists example.net. This PC did the lookup. Flush again, run curl --socks5-hostname, and the cache stays empty while the request still returns 200. The proxy did the lookup. The Tor Project names the stake in its SOCKS documentation, revised March 2026. "If clients do their own DNS lookup, the DNS server can learn which addresses the client wants to reach."
The IPv6-only test closes the SOCKS4 case. Against ipv6.google.com, which has only AAAA records, curl --socks4 gave up before contacting the proxy, with a negative name resolve in its log. curl --socks4a reached our server, which could not resolve the name to IPv4 and answered 91. --socks5 and --socks5-hostname both returned 200. SOCKS4 cannot carry a 16-byte address, whoever resolves the name.
Does SOCKS5 really give you UDP and IPv6?
The protocol does. Public proxies mostly do not. On 2 September 2026 we pulled the 40 highest-uptime SOCKS5 entries and the 40 highest-uptime SOCKS4 entries from our free list, 50 distinct proxies, and sent each one seven separate raw-socket requests. No credentials, no paid endpoints, an 8-second timeout.
- 40 listed as SOCKS5
- 40 listed as SOCKS4
Three findings stand out:
- The label means little. 38 of the 40 SOCKS5 entries also granted a SOCKS4 CONNECT, and 32 of the 40 SOCKS4 entries also completed a SOCKS5 connection by hostname. 30 of the 40 SOCKS5 entries were listed under both protocols anyway. At 10:11 UTC that day the list held 5,930 SOCKS5 and 3,069 SOCKS4 entries.
- IPv6 mostly fails. 17 of 40 SOCKS5 entries completed a CONNECT to an IPv6 address. 20 answered
0x03network unreachable: they parsed the address type and had no route. On the SOCKS4 list the figure was 9 of 40. - UDP is a handshake that goes nowhere. 19 of 40 SOCKS5 entries accepted UDP ASSOCIATE and 19 answered
0x07. Of the 19 that accepted, 17 returned a relay port of 0, one returned a private address, and one returned a real address that never relayed the datagram we sent. Zero of 40 relayed one DNS query. Our own UDP proxy checker, which does the same test, reported no UDP support for all 12 entries we gave it.
Two large SOCKS5 servers do not offer UDP by design. Tor's documentation lists "UDP ASSOCIATE" under commands it does not support, and Chromium's proxy documentation says SOCKS5 in Chrome "cannot be used to relay UDP traffic". If you need UDP through a proxy, you need a SOCKS5 endpoint that advertises it and a test that proves it.
Is SOCKS5 more secure than SOCKS4?
SOCKS5 controls who may use the proxy. Neither version protects what flows through it.
The authentication step is real. When we offered public proxies both no-auth and username/password, 38 of 39 that answered picked no-auth and one picked username/password. A commercial endpoint picks 0x02 and refuses to relay until the login checks out. That login travels in the clear. RFC 1929 says so in its security section. "Since the request carries the password in cleartext, this subnegotiation is not recommended for environments where sniffing is possible and practical."
Encryption exists in the standard only through the GSS-API method. RFC 1961 defines "a GSS-API-based encapsulation for provision of integrity, authentication and optional confidentiality". Almost nobody ships it. Chromium's documentation says "no authentication methods are supported for SOCKSv5 in Chrome". Tor's says GSS-API is "not supported, even though they are listed as MUST support by RFC 1928". In practice your traffic is private because TLS is inside the tunnel, or because the tunnel is ssh -D. The OpenSSH manual (August 2026) describes ssh -D as acting "as a SOCKS server" for both "SOCKS4 and SOCKS5".
One number matters more than the version. We opened a TLS session to example.com:443 through each of the 50 public proxies and read the certificate that came back. Two delivered the genuine one. 44 delivered a certificate signed by something else. 26 were signed by "None, LLC" and one by a Check Point inspection firewall. The rest carried names such as "Security-DVR-X7W1", "router.local" and "SCADA-Server", which suggest the tunnel never reached example.com at all. curl refused every HTTPS request through 14 of them with exit code 60, an untrusted certificate. A SOCKS5 login does nothing about that. The endpoint does. This is the whole argument of when free proxies are fine, measured.
When is SOCKS4 still the right choice?
Rarely, and never for a reason of speed. The four candidates:
- The tool speaks nothing newer. Some old clients and embedded firmware offer only SOCKS4. Prefer SOCKS4a if the setting exists, so the proxy resolves the name.
- The endpoint speaks nothing newer. A SOCKS4-only proxy is a fact you test, not a preference. Most entries on public lists turned out to speak both.
- The target is an IPv4 address you already hold. With no hostname to resolve, no password to send and no UDP, SOCKS4 loses nothing. This is the one honest case.
- A chain where every hop must be SOCKS4. proxychains and similar tools accept
socks4andsocks5per hop; pick the version the hop actually supports, and test it.
Two browsers show how little room is left. Chromium's documentation states that Chrome "does not allow configuring, or falling back to v4a", and that SOCKS4 name resolution "is always done client side" and "must resolve to an IPv4 address". Firefox goes further in its source: when the destination is an IPv6 address, a SOCKS4 proxy setting is silently switched to SOCKS5. The OpenBSD nc manual (June 2025) puts it plainly: SOCKS v.4 "is very limited and can only be used when the destination host can be resolved to an IPv4 address".
How do you tell which one a proxy speaks?
Ask it. A SOCKS5 server answers the three-byte greeting 05 01 00 with 05 00. A SOCKS4 server answers a CONNECT request with a reply whose first two bytes are 00 5A (decimal 90). A server that closes the connection or sends anything else does not speak that version. Then push a real request through, because a granted handshake is not a relayed connection. In our probe, eight cloud-hosted entries answered a SOCKS4 CONNECT with 90 and then returned an HTTP 400 from something that was not example.com. Our proxy checker, which relays a request to an endpoint we control, marked those eight dead as SOCKS4 and alive as SOCKS5.
It does the same for the newer version, and reports protocol, anonymity, exit country, network and latency per line. Paste a list, and the column that said "SOCKS5" becomes a fact.
Which flag or setting changes in curl, Firefox, Chrome, ssh and Python?
| Client | SOCKS4, client resolves | SOCKS4a, proxy resolves | SOCKS5, client resolves | SOCKS5, proxy resolves | Source |
|---|---|---|---|---|---|
| curl | --socks4 or socks4:// | --socks4a or socks4a:// | --socks5 or socks5:// | --socks5-hostname or socks5h:// | curl manual, 8.16.0 |
| Python requests | not offered | not offered | socks5:// | socks5h:// | requests docs, revised May 2026 |
| Firefox | SOCKS v4 | SOCKS v4 with network.proxy.socks_remote_dns set to true (default false) | SOCKS v5 with network.proxy.socks5_remote_dns set to false | SOCKS v5 (default true) | Firefox source, read 2 September 2026 |
| Chrome | socks4://host:port | not offered | not offered | socks5://host:port | Chromium proxy docs, revised November 2025 |
OpenSSH ssh -D | serves it | serves it | serves it | serves it | ssh(1), August 2026 |
OpenBSD nc -X | -X 4 | -X 4A | -X 5 sends the name | -X 5 (default) | nc(1), June 2025 |
Python requests states the convention it borrowed. "Using the scheme socks5 causes the DNS resolution to happen on the client, rather than on the proxy server. This is in line with curl." Firefox documents its two prefs in the source. socks_remote_dns makes SOCKS4 "a SOCKS4a proxy", and socks5_remote_dns makes SOCKS5 "a SOCKS5h proxy by convention".
Which should you use?
SOCKS5, with the proxy resolving names, in every case where you have the choice. It does everything SOCKS4 does and adds a login, IPv6, remote DNS and a UDP command. SOCKS4 loses this comparison on every row except one, the case where you connect to an IPv4 address you already hold. SOCKS4a is the version to prefer over plain SOCKS4 when a tool offers it.
Then pick the endpoint with more care than the version. On a public list, the version protects you from nothing we measured: 44 of 50 proxies forged the certificate, none relayed UDP, and fewer than half reached IPv6. A SOCKS5 endpoint you pay for is a different object. Our residential and datacenter proxies speak SOCKS5 with username and password alongside HTTP, resolve names on the proxy, and relay to the host you asked for. Pick SOCKS5 for the protocol, then pick an IP worth routing real work through.
Sources
- SOCKS Protocol Version 5, RFC 1928, IETF, March 1996. Handshake, methods, commands, address types, reply codes, UDP relay.
- Username/Password Authentication for SOCKS V5, RFC 1929, IETF, March 1996. The subnegotiation and its cleartext note.
- GSS-API Authentication Method for SOCKS Version 5, RFC 1961, IETF, June 1996. Integrity and optional confidentiality.
- SOCKS: A protocol for TCP proxy across firewalls, Ying-Da Lee, NEC Systems Laboratory, undated, cited by RFC 1928. Copy hosted by the OpenSSH project.
- SOCKS 4A: A Simple Extension to SOCKS 4 Protocol, Ying-Da Lee, undated. Copy hosted by the OpenSSH project.
- Service Name and Transport Protocol Port Number Registry and SOCKS Methods registry, IANA, read 2 September 2026.
- curl manual, options --socks4, --socks4a, --socks5, --socks5-hostname and --proxy, curl project, version 8.16.0, September 2025.
- ssh(1) manual page, OpenSSH, OpenBSD, August 2026; nc(1) manual page, OpenBSD, June 2025.
- Proxy support in Chrome, net/docs/proxy.md, The Chromium Project, revised November 2025.
- Firefox source: modules/libpref/init/StaticPrefList.yaml, netwerk/base/nsProtocolProxyService.cpp and netwerk/socket/nsSOCKSIOLayer.cpp, Mozilla, mozilla-central, read 2 September 2026.
- Tor's extensions to the SOCKS protocol, The Tor Project, torspec, revised March 2026.
- Advanced usage: SOCKS, python-requests documentation, revised May 2026.
- HProxy measurements, 2 September 2026: raw-socket probe of 80 public SOCKS entries, UDP relay test, TLS certificate check, curl wire test through a logging SOCKS server, DNS cache test. Method and raw results are recorded in the page's research folder.


