Why Network Ports Go From 0 to 65535: The 16-Bit Story
Port numbers stop at 65535 because TCP and UDP store them in a 16-bit field. Here is what that means, how IANA splits the range, and why low ports need root.
You have probably seen :8080, :443, or :3000 hanging off the end of an address and never wondered why the ceiling is 65535 and not, say, 100000. The number is not arbitrary. It falls directly out of how many bits TCP and UDP set aside to store a port.
It is a 16-bit field, so the math is fixed
Both the TCP and UDP headers reserve exactly 16 bits for the source port and 16 bits for the destination port. A 16-bit unsigned integer can represent 2^16 = 65536 distinct values. Counting from zero, that gives you the inclusive range 0 to 65535. There is no extra register, flag, or extension that grows it; the size of the field is the size of the address space.
This is the same reason an 8-bit byte tops out at 255 (2^8 - 1) and a classic unsigned short in C tops out at 65535. A port is, quite literally, an unsigned short. If you ever try to bind to port 70000, the library either rejects it or silently wraps the value, because the number simply does not fit in the slot the protocol gives it.
A port is not a physical thing. It is a label inside a packet that lets one machine run many network services at once. Your laptop has one IP address but can talk to a web server, an SSH daemon, and a database simultaneously because each conversation is tagged with a different port. The operating system uses the combination of (protocol, source IP, source port, destination IP, destination port) to route each packet to the right socket.
How IANA carves up the 65536 values
The numbers themselves are just integers, but the Internet Assigned Numbers Authority (IANA) splits the range into three conventional zones so that software agrees on where common services live:
- Well-known / system ports — 0 to 1023. These are the famous ones: HTTP on 80, HTTPS on 443, SSH on 22, DNS on 53, SMTP on 25. They are assigned for standard services so that a client can connect to
https://example.comwithout being told the port. - Registered ports — 1024 to 49151. Vendors and projects register these with IANA for specific applications, but they are not as tightly controlled. PostgreSQL’s default 5432 and MySQL’s 3306 live here.
- Dynamic / private / ephemeral ports — 49152 to 65535. Nobody owns these. The OS hands them out temporarily for the client side of a connection.
That last category is the one you rarely type but use constantly. When your browser opens a connection to port 443 on a server, your own machine needs a return address too. It grabs a free ephemeral port for the duration of that connection and releases it afterward. Open 30 browser tabs and your OS is juggling dozens of ephemeral ports behind the scenes.
Why low ports need elevated privileges
On Unix-like systems, binding to any port below 1024 traditionally requires elevated privileges (root, or a specific capability like CAP_NET_BIND_SERVICE on Linux). Ports at or above 1024 can be bound by ordinary users.
The reason is historical and security-minded. The well-known ports map to trusted services, so the rule prevents an unprivileged user from, say, starting a fake SSH server on port 22 and harvesting other people’s passwords. The cost is friction: it is why a Node or Python dev server defaults to something like 3000 or 8080 instead of 80, and why production setups often run the app on a high port and put a privileged reverse proxy in front to listen on 80 and 443.
You can verify which ports are listening with a quick command:
# macOS / Linux
ss -tlnp # or: lsof -i -P -n | grep LISTEN
FAQ
The port number ceiling is one of those facts that looks like a magic constant but is really just a consequence of a design decision made decades ago: give each port a 16-bit slot in the packet header, and 65535 is what you get.
FAQ
Can the same port number be used by both TCP and UDP at once?
Why does it start at 0 and not 1?
Could ports ever go higher than 65535?
Related reading
2026-06-22
TCP vs UDP, Explained Through What Breaks When You Pick Wrong
TCP and UDP aren't interchangeable. We walk through the exact failure modes — head-of-line blocking, silent packet loss, Nagle delays — that show up when you pick the wrong transport.
2026-06-22
Write-Ahead Logging: How Databases Survive a Power Cut
How write-ahead logging keeps your data intact when the machine dies mid-write — the log-first rule, fsync, checkpoints, and why PostgreSQL and SQLite both rely on it.
2026-06-22
Backpressure, Explained Through a Queue That Won't Fall Over
What backpressure actually is, why an unbounded queue is a memory leak in disguise, and the four strategies a producer can take when a consumer falls behind.
2026-06-22
What a Bloom Filter Actually Saves You (and When It Lies)
A bloom filter trades a small false-positive rate for big memory savings. Here is the math behind the trade, where it pays off, and the failure mode that bites people.
2026-06-22
Idempotency, Explained Through the Retry That Doesn't Double-Charge
A practical look at idempotency keys: why a retried payment request shouldn't charge a card twice, how the pattern works, and where it quietly breaks in production.
Get the best tools, weekly
One email every Friday. No spam, unsubscribe anytime.