SO_REUSEPORT changes a local endpoint from a single-socket binding into a socket group. On Linux, multiple TCP or UDP sockets can bind the same local address when every participating socket enables the option before bind() and the bind credentials satisfy the kernel’s reuse rules.
That behavior is distinct from merely relaxing address-conflict checks. Incoming traffic must also be assigned to one member of the group. The resulting selection boundary affects listener architecture, queue isolation, process restarts, UDP flow placement, and any design that assumes a port maps to exactly one socket.
One address can represent several sockets
A conventional TCP server commonly creates one listening socket:
int fd = socket(AF_INET, SOCK_STREAM, 0);
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
listen(fd, 512);Worker threads may all call accept() on that descriptor, but they still contend around one listening socket and its queues.
With SO_REUSEPORT, each worker can own a separate socket bound to the same address:
int one = 1;
int fd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
listen(fd, 512);Repeating that sequence in eligible workers creates multiple listeners for the same endpoint. The kernel selects a listener before the application calls accept(). Each selected connection then appears on the queue associated with that listener.
The distinction moves traffic distribution below the application accept loop. It also means each listener has independent socket state, queue occupancy, file descriptor lifetime, and owning execution context.
Every member must opt in before binding
SO_REUSEPORT is not a flag that one socket can apply retroactively to an existing unrelated listener. For an eligible shared bind, each socket sets the option before bind().
This ordering is operationally significant during process replacement. A new process cannot assume that enabling the option will let it join a port held by a listener that was created without compatible reuse settings.
Linux also applies an effective-user-ID constraint to sockets joining a reuse-port group. The constraint blocks an unrelated user from opening another listener on an occupied reusable endpoint and receiving a portion of its traffic.
These conditions make reuse-port membership a property established during socket setup, not a generic permission to attach to arbitrary bound ports.
TCP selection occurs before accept
For TCP, a reuse-port group can replace one shared listener with several listeners. New connections are assigned among those sockets by kernel selection logic. Application workers no longer need to race on the same listening file descriptor to divide accepted connections.
This architecture changes the scope of queue pressure. If one worker stops calling accept(), its listener can accumulate pending work independently of another listener that is being drained promptly. A healthy sibling does not simply consume entries already assigned to the stalled socket.
The kernel’s selection mechanism can improve distribution, but it does not make worker health uniform. Per-listener backlog state and scheduling still matter. A process model that uses one listener per CPU or worker therefore gains isolation while also creating several queue domains that require separate operational attention.
UDP keeps datagram boundaries but adds socket selection
For UDP, there is no accept queue. Each incoming datagram must still be directed to one socket in the group.
That makes SO_REUSEPORT useful for parallel receive paths without forcing several workers to read from one shared descriptor. Each worker can block on or poll its own socket, and the kernel performs group selection before delivery.
Selection is not equivalent to copying. A datagram assigned to one group member is not delivered to every member merely because they share the local address. Applications that require fan-out semantics need a different mechanism.
Stable placement can also matter for protocols built over UDP. If related datagrams are expected to reach the same worker, the selection policy becomes part of application behavior rather than a minor bind detail.
Reuse-port BPF can replace default selection
Linux exposes SO_ATTACH_REUSEPORT_CBPF and SO_ATTACH_REUSEPORT_EBPF for reuse-port groups. A program attached through these options can influence which socket receives traffic.
For classic BPF reuse-port selection, the program returns a socket index. Extended BPF also supports reuse-port-specific programs and socket selection through the relevant helper. Invalid classic selections fall back to the kernel’s plain reuse-port mechanism.
This facility turns the group from a fixed kernel-distribution primitive into a programmable dispatch boundary. Selection can account for packet or socket context available to the BPF program, subject to verifier and program-type constraints.
Group membership is dynamic. Sockets are indexed according to group ordering rules, and removal can change index placement. A selector that treats a numeric index as a permanent worker identity can therefore become incorrect as sockets enter or leave the group.
SO_REUSEPORT and SO_REUSEADDR solve different problems
SO_REUSEADDR and SO_REUSEPORT are often placed next to each other in socket setup code, but they do not express the same contract.
SO_REUSEADDR alters address-validation rules used by bind(). It is commonly relevant when rebinding local addresses across socket lifecycle states. It does not, by itself, create a group of active TCP listeners that receive distributed new connections.
SO_REUSEPORT explicitly permits eligible sockets to bind an identical address and provides a receive-selection mechanism for the resulting group.
Treating the two options as interchangeable can hide deployment defects. A server may restart cleanly with one option yet still fail to support concurrent old and new listener sets, or it may bind successfully without obtaining the intended traffic-distribution model.
Process replacement gains a concurrency window
A reuse-port design can allow an old server generation and a new generation to hold compatible listeners on the same endpoint at the same time. That creates a useful overlap window for process replacement.
The overlap is not a handoff transaction. While both generations remain in the group, new traffic can be selected for either generation according to the active selection policy. Closing old listeners removes them from future group selection, but connections already accepted by the old process remain owned by that process until their own lifecycle ends.
As a result, graceful replacement has at least two separate boundaries: removal of old listeners from new-connection selection, and completion or termination of established connections already owned by the old generation.
A deployment system that conflates those boundaries can report a listener transition as complete while substantial connection state still exists in the retiring process.
Socket groups move balancing into the kernel boundary
SO_REUSEPORT changes the unit attached to a local address. The endpoint can represent a group of independently owned sockets, with kernel logic selecting the receiver before normal application-level processing.
That shift can reduce contention on a shared descriptor and align socket ownership with worker ownership. It also exposes per-socket queue state, group membership changes, credential constraints, and selection policy as parts of the server’s runtime behavior.
The option is therefore more than a bind convenience. It defines a dispatch boundary whose state persists independently across the sockets participating in the group.