Every proxy list still has a SOCKS4 column next to the SOCKS5 one, and most people picking between them are guessing. The two are not just version numbers apart, they are separated by four concrete capabilities that decide whether a given tool will even work: authentication, IPv6, who resolves your DNS, and whether UDP is on the table. Once you have seen the wire format of each, the choice stops being a guess.
We run a proxy network and read the specs so this is not a summary of a summary. Both are short. Here is what SOCKS4 actually put on the wire, what SOCKS4a bolted on, and what SOCKS5 rebuilt, byte by byte where it matters.
SOCKS4: the original, and its walls
SOCKS4 is tiny. A client opening a connection sends a single request packet, and the SOCKS4 protocol specification lays out its fields exactly:
- VN, 1 byte: the version, "should be 4".
- CD, 1 byte: the command, "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" to terminate the userid.
The proxy replies with its own small packet: a VN byte that "should be 0", then a result code. The codes are 90 for "request granted", 91 for "request rejected or failed", 92 for rejected "because SOCKS server cannot connect to identd on the client", and 93 for a mismatch where "the client program and identd report different user-ids". Those last two are a window into SOCKS4's era: its idea of authentication was identd, a now largely abandoned protocol for asking a remote machine who owns a connection.
Read those fields again and SOCKS4's three walls are right there in the layout. DSTIP is 4 bytes, so the destination is IPv4 only, no IPv6 will fit. The command set is CONNECT and BIND, both TCP, so there is no UDP. And because the destination is sent as an IP, not a name, your client has to resolve the hostname to an address before it sends the request. That last one has a privacy cost people miss: your DNS lookup goes out through your own local resolver, so even though your traffic is proxied, your machine has already told its resolver every domain you are about to visit.
SOCKS4a: a hostname patch
SOCKS4a is a small extension for exactly that DNS problem, written for "hosts which are not capable of resolving all domain names." It reuses the SOCKS4 packet with one trick. Per the SOCKS4a specification, the client sets "the first three bytes of DSTIP to NULL and the last byte to a non-zero value", producing the reserved form 0.0.0.x. That impossible address is a flag: it tells the proxy no real IP is coming. Then, after the usual USERID null byte, "the client must send the destination domain name and terminate it with another NULL byte." The proxy sees the 0.0.0.x marker, reads the appended hostname, and resolves the DNS itself.
That is the ancestor of every "remote DNS" feature you use today. It moves the lookup from your machine to the proxy, which both fixes the leak and lets clients that cannot resolve names still reach them. SOCKS4a is strictly this hostname bolt-on, though: still IPv4 destinations for the resolved address, still TCP only, still no real authentication.
SOCKS5: a redesign, not a bump
SOCKS5, defined in RFC 1928, is not SOCKS4 with a higher number, it is a different, negotiated protocol. Instead of one fire-and-forget request, it opens with a short handshake. The client greets the proxy with a version byte (0x05, the literal 5) and the list of authentication methods it supports. The proxy picks one and answers: commonly 0x00 "no authentication required", or 0x02 username and password, defined in RFC 1929; if nothing offered is acceptable it returns 0xFF and hangs up. Only then does the client send its actual request.
That structure is what carries every SOCKS5 upgrade over SOCKS4:
- Real authentication. The method negotiation means a proxy can require username and password before it relays anything, which is how commercial SOCKS5 endpoints gate access. (The caveat, straight from RFC 1929: the password travels in cleartext during the handshake, so it controls access without protecting data.)
- More commands. The request command byte is
0x01CONNECT,0x02BIND, or0x03UDP ASSOCIATE. That third one is entirely new: SOCKS5 can relay UDP datagrams, which SOCKS4 simply could not. - Three address types. An
ATYPbyte says how to read the destination:0x01for a 4-byte IPv4 address,0x04for a 16-byte IPv6 address, or0x03for a domain name. IPv6 and native hostname support both arrive here, and the domain-name type makes remote DNS a first-class feature instead of the0.0.0.xhack SOCKS4a needed.
We walk through the full SOCKS5 handshake, including the socks5 versus socks5h distinction for where DNS gets resolved, 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, which SOCKS4 could never do and SOCKS4a only faked.
The three side by side
| SOCKS4 | SOCKS4a | SOCKS5 | |
|---|---|---|---|
| Version byte | 0x04 | 0x04 | 0x05 |
| Transport | TCP | TCP | TCP and UDP |
| Destination address | IPv4 only | IPv4, or hostname via 0.0.0.x | IPv4, IPv6, or hostname |
| Who resolves DNS | Your client | The proxy | Your client or the proxy |
| Authentication | userid / identd | userid / identd | None or username/password (and more) |
| UDP relaying | No | No | Yes (UDP ASSOCIATE) |
| IPv6 | No | No | Yes |
| Encryption | None | None | None |
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, because no version of SOCKS encrypts anything. If your connection is private, that is TLS doing the work, regardless of which SOCKS version carried it.
So which do you use?
SOCKS5, essentially always. It does everything SOCKS4 does, adds authentication, IPv6, remote DNS, and UDP, and costs you nothing in complexity for ordinary TCP work. SOCKS4 and SOCKS4a are worth understanding because you will still meet them on old tooling and public lists, and now you know precisely what you give up by using them: no UDP, no IPv6, and, on plain SOCKS4, a DNS leak baked into the design.
For anything past experimentation, the version matters less than the IP behind it, because a free SOCKS4 or SOCKS5 proxy off a public list is shared, short-lived, and often already flagged (we cover the limits in when free proxies are fine). Our paid residential and datacenter proxies speak SOCKS5 alongside HTTP, so you get the modern protocol and an IP worth routing real work through, and our proxy checker will confirm whether any endpoint you paste really is SOCKS5 and what it exposes. Pick SOCKS5 for the protocol, then pick the IP quality for the job.
Sources and further reading
- SOCKS4: A protocol for TCP proxy across firewalls. The SOCKS4 request and reply packet layout, the
90to93reply codes, and the identd-based userid check. - SOCKS 4A: A Simple Extension to SOCKS 4 Protocol. How the
0.0.0.xdestination marks that a hostname follows the userid, so the proxy resolves DNS for clients that cannot. - RFC 1928: SOCKS Protocol Version 5. The negotiated handshake, the CONNECT / BIND / UDP ASSOCIATE commands, and the IPv4 / domain-name / IPv6 address types that give SOCKS5 remote DNS and IPv6.
- RFC 1929: Username/Password Authentication for SOCKS V5. The optional auth exchange, and its own statement that the password is sent in cleartext.