All articles
169 articles · updated weekly See our Tools
All articles
Tutorials

Network ports: what they are and what they do

Network ports explained: what they are and what they do, how they work in practice, and when this actually matters in real projects.

Network ports: what they are and what they do
COVER · Tutorials

The day "address already in use" taught me networking

I spun up a new service in staging, ran docker compose up, and the container died on launch: bind: address already in use. I spent twenty minutes looking in the wrong place — I assumed it was the database, but it was a zombie process from a previous deploy still holding port 5432. The missing piece wasn't in the code, it was in the layer underneath: how a machine decides which program gets a packet that arrives. That's the job of ports, and almost every "network bug" starts with not understanding this properly.

The plan here is to take the concept of a network port apart without loose theory: what it is, how the system uses it, and where it bites you day to day. Since a port never exists alone — it's always glued to a transport protocol — it's worth reading the TCP vs UDP comparison too, because half your port decisions depend on which of the two you're using.

What a port actually is

An IP identifies a machine on the network. The problem is that a machine runs dozens of programs at once that all want to talk to the network: the web server, the database, SSH, your email client. If only the IP existed, the operating system would receive a packet and not know who to hand it to.

The port is the number that solves this. If the IP is the building's street address, the port is the apartment number. The packet reaches the building (IP) and the doorman (kernel) reads the destination port to know which apartment (process) to deliver it to. It's a 16-bit number, so it ranges from 0 to 65535.

The real unit of a connection isn't the port alone, it's what's called a socket: the combination ip:port plus the protocol. 192.168.0.10:443 over TCP is a different socket from 192.168.0.10:443 over UDP. They're independent stacks. That's why the same port number can be "occupied" on TCP and free on UDP at the same time.

Well-known, registered, and ephemeral

The range of 65536 ports isn't a flat free-for-all. It's split by convention:

  • 0–1023 (well-known): the famous ports, reserved for standard services. On Unix systems, binding one of these requires root privilege. Examples: 22 (SSH), 80 (HTTP), 443 (HTTPS), 53 (DNS).
  • 1024–49151 (registered): assigned to specific applications but without requiring root. This is where a lot of infra lives: 5432 (PostgreSQL), 3306 (MySQL), 6379 (Redis), 8080 (alternate HTTP).
  • 49152–65535 (ephemeral/dynamic): the system uses these for the client side. When your browser opens a connection to a server on 443, it gets assigned a random ephemeral port itself to receive the reply.

That last part trips a lot of people up. Port 443 is the server's. Your side of the conversation uses a high, disposable port, created on the spot and released when the connection closes. That's why one machine can hold thousands of simultaneous connections to the same server: each one has a different source port.

Who listens and who connects

There are two clearly distinct roles, and it's worth keeping them separate in your head:

A process that listens reserves a port and sits there waiting for connections to arrive. That's the server. It calls bind() on the port and listen(). Only one process can listen on a given ip:port:protocol combination at a time — hence address already in use.

A process that connects is the client: it fires a connect() at the server's ip:port and the system hands it an ephemeral source port automatically. Clients don't need to reserve a port in advance.

When you're debugging an address or trying to understand which port a host exposes to the outside, it helps to look at its network context — block, IP type, reverse DNS. The IP Address Info tool is useful exactly there: you paste the address and see what can be inferred before you go scanning.

How to see what's listening

When something won't start or a port seems "stuck", you need to look at the kernel's real state, not your guess. On modern Linux, ss is the tool:

# TCP, listening, with process name and numeric port (no DNS resolution)
ss -tlnp

# Filtering a specific port
ss -tlnp 'sport = :5432'

On older machines or other systems, netstat does the equivalent:

netstat -tlnp        # Linux
netstat -ano         # Windows (shows the PID in the last column)

The output gives you the trio that matters: the port, the state (LISTEN, ESTABLISHED), and the owning PID. That's how I killed the zombie from the top of this post — ss -tlnp showed the PID holding 5432, a kill fixed it, and compose up came up.

Why you get "address already in use" and firewalls

address already in use is almost always one of three things: a process of yours is still running and holding the port; another legitimate application is using that number; or the previous connection is in TIME_WAIT state and the kernel hasn't released the socket yet. The first two you fix by finding the PID and deciding what to do. The third is normal and clears on its own in a few seconds — or you use SO_REUSEADDR on the server to allow an immediate rebind.

Firewalls are the other half of the story, and the classic confusion is thinking a port is "closed" when really the service isn't even listening. They're different things:

  • Nothing listening: connection refused immediately (connection refused).
  • Firewall blocking: the packet is dropped silently and you get a timeout, not a refusal.

Exposing a port to the internet is a security decision, not a convenience one. Practical rule: only expose what needs to be public (usually 443), and keep your database, Redis, and SSH behind a firewall, a VPN, or bound to 127.0.0.1. A database listening on 0.0.0.0:5432 open to the world is one of the fastest ways to make headlines.

Frequently asked questions

Can two applications use the same port?

Not listening on the same ip:port:protocol combination at the same time. But the same number can be free on different protocols (TCP vs UDP) or on different IPs of the same machine. And any number of clients can connect to one server port — what's unique is each connection's socket, not the destination port.

Why do some ports require root to open?

On Unix systems, ports 0 through 1023 are privileged by historical security convention: only processes with elevated privilege can bind to them, to stop any random program from impersonating a standard service like HTTP or SSH. That's why web servers often start as root just to bind 80/443 and then drop the privilege.

What's the difference between a closed and a filtered port?

Closed means nobody is listening there — the machine actively responds by refusing the connection. Filtered means a firewall is dropping the packets without responding, so you only notice via timeout. From the outside, "refused fast" suggests a closed port; "hung" suggests a firewall.

Does changing a service's port improve security?

Only marginally. Running SSH on 2222 instead of 22 cuts the noise from bots scanning the default port, but it won't stop an attacker doing a real scan. It's camouflage, not defense. Real security comes from strong authentication, firewalls, and exposing the minimum — not from hiding the number.

What to take from this

A port is the mechanism that lets a single machine talk to the network on behalf of dozens of processes at once. What matters to remember: the real unit is the socket (ip:port + protocol), not the port alone; the server listens on a fixed port while the client gets an ephemeral one; and almost every problem that looks "network-related" is, in practice, either a process holding a port or a firewall silently dropping a packet. When things break, don't guess — run ss -tlnp and look at the real state before touching any config.

RD
Author
Rafael Duarte
Backend developer with a background in fintech and B2B SaaS — worked on teams that scaled APIs from zero to millions of requests. Carries enough production scars to hold strong opinions on tools, patterns and architecture decisions. Not an academic: he read the UUID RFC when he had to choose between v4 and v7 for a write-heavy table.
View profile