TCP port exhaustion occurs when a system depletes its available ephemeral ports for outgoing connections. The available ranges vary significantly by OS:
// Windows (pre-Vista): 1025-5000 (3976 ports)
// Windows (Vista+): 49152-65535 (16384 ports)
// Linux (default): 32768-60999 (28232 ports)
// macOS: 49152-65535 (16384 ports)
The port pool behavior depends on implementation:
- Global pool: Most OS versions maintain a single shared pool for all destinations
- Per-destination pool: Some BSD variants partition ports by remote IP
Using the TIME_WAIT duration (2MSL) constraints:
// Windows (240s timeout):
max_rate = 3976 ports / 240s ≈ 16.5 ports/second
// Linux (60s timeout):
max_rate = 28232 ports / 60s ≈ 470 ports/second
Real-world cases where this matters:
# Load testing scenario that could trigger exhaustion
ab -n 100000 -c 500 http://example.com/
# Python script that demonstrates rapid connection creation
import socket
for i in range(50000):
s = socket.socket()
s.connect(('example.com', 80))
# Without proper close, ports remain allocated
Configuration improvements:
# Linux: Increase port range
echo "32768 61000" > /proc/sys/net/ipv4/ip_local_port_range
# Windows: Adjust TIME_WAIT duration
netsh int ipv4 set dynamicport tcp start=10000 num=50000
Application-level solutions:
// Connection pooling example in Node.js
const { createPool } = require('generic-pool');
const pool = createPool({
create: () => net.createConnection(3306, 'db.example.com'),
destroy: (client) => client.end()
});
Diagnostic commands for different platforms:
# Linux: Check used ports
ss -tan | awk '{print $4}' | awk -F: '{print $NF}' | sort -n | uniq -c
# Windows: Active connections
netstat -ano | find "TIME_WAIT" | find /c "TCP"
Port exhaustion becomes a concern when:
- Running high-throughput services (API gateways, proxies)
- Implementing microservices with frequent inter-service calls
- Conducting load testing without connection pooling
Modern operating systems allocate different ranges for ephemeral ports:
- Legacy Windows systems: ~4,000 ports (1025-5000)
- Modern Windows: ~16,384 ports (49152-65535)
- Red Hat Linux: ~28,000 ports (32768-60999)
The critical factor in port exhaustion is the TIME_WAIT state duration:
// Typical TIME_WAIT durations: #define WINDOWS_TIME_WAIT 240 // seconds #define LINUX_TIME_WAIT 60 // seconds
To calculate the minimum allocation rate that would cause exhaustion:
// Formula: ports_available / TIME_WAIT_duration Windows (legacy): 4000 / 240 ≈ 16.67 ports/sec Windows (modern): 16384 / 240 ≈ 68.27 ports/sec RHEL Linux: 28000 / 60 ≈ 466.67 ports/sec
The actual behavior depends on several factors:
- Global vs per-destination allocation: Most modern OSes implement some form of port selection algorithm that considers the destination
- Port randomization: Security features may affect allocation patterns
- Connection reuse: HTTP keep-alive can significantly reduce port usage
Practical examples for checking port usage:
# Linux: Check used ports ss -tulnp | wc -l # Windows: PowerShell command Get-NetTCPConnection -State TimeWait | Measure-Object | Select-Object -ExpandProperty Count
When approaching port exhaustion:
// Linux sysctl tweaks (RHEL/CentOS) net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30 // Windows registry adjustment [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] "MaxUserPort"=dword:0000fffe "TcpTimedWaitDelay"=dword:0000001e
Practical considerations:
- Most web servers won't hit these limits unless handling thousands of requests/sec
- Microservices architectures with many outbound connections are more vulnerable
- Connection pooling is your friend - implement it properly
A case where port exhaustion actually occurred:
// Node.js service hitting limits const http = require('http'); // Bad pattern - creating new connections for each request function makeRequest() { http.get('http://downstream.service', (res) => { // process response }); } // Solution - reuse connections with keep-alive const agent = new http.Agent({ keepAlive: true }); function betterRequest() { http.get('http://downstream.service', { agent }, (res) => { // process response }); }