Ephemeral port exhaustion behind NAT: the failure that looks like DNS
When clients behind a NAT device suddenly cannot reach external services, the first instinct is to blame DNS. Users report 'the internet is down' or 'DNS is broken.' But tcpdump shows DNS queries resolving correctly, and the authoritative nameserver logs show no errors. The real culprit is often ephemeral port exhaustion at the NAT layer--a failure mode that masquerades as a DNS problem because it strikes at the moment a client tries to establish a new connection.
How NAT port allocation works
A NAT device translates private source addresses and ports into public addresses and ports for outbound traffic. Each outbound connection requires a mapping entry in the NAT translation table. The source port (ephemeral port) is drawn from a pool, typically UDP ports 49152-65535 and TCP ports 49152-65535 on most systems, though some implementations use smaller ranges like 1024-65535.
When a connection closes, that port is returned to the pool. But if the port is still in TIME_WAIT state (typically 60 seconds for TCP), it cannot be reused immediately. If new connections arrive faster than old ones age out, the pool empties. Once all ephemeral ports are exhausted, no new outbound connections can be established--even though DNS works perfectly.
Why it looks like DNS
DNS queries are small and often cached, so they may succeed even when ephemeral ports are depleted. A client can resolve www.example.com without consuming a port from the main pool if the result comes from the local resolver cache. But the moment the application tries to open a TCP connection to the resolved IP address, the SYN packet fails silently. The client sees a connection timeout or 'host unreachable' error, which users interpret as 'DNS is broken' because the name resolution appeared to work.
Diagnosing ephemeral port exhaustion
Look for these indicators on the NAT device:
- →High number of connections in TIME_WAIT state (netstat -an | grep TIME_WAIT | wc -l)
- →Translation table at or near maximum capacity (vendor-specific commands; check your NAT logs)
- →Intermittent connection failures that resolve when traffic subsides
- →Successful DNS queries followed immediately by connection timeouts
- →Asymmetric failures: outbound connections fail, but inbound (if applicable) succeed
# On a Linux NAT gateway, check ephemeral port usage ss -tan | grep TIME_WAIT | wc -l # View the current range cat /proc/sys/net/ipv4/ip_local_port_range # Check translation table size (if using iptables) cat /proc/net/nf_conntrack | wc -l cat /proc/sys/net/netfilter/nf_conntrack_max
Remediation strategies
- →Expand the ephemeral port range: increase ip_local_port_range on Linux or equivalent on your NAT platform
- →Reduce TIME_WAIT duration: lower tcp_fin_timeout (Linux) or equivalent, but be aware of potential issues with duplicate packets
- →Increase NAT translation table size: raise nf_conntrack_max or vendor-specific limits
- →Implement connection pooling on clients to reduce connection churn
- →Distribute clients across multiple NAT gateways or use connection multiplexing protocols like HTTP/2
- →Monitor NAT gateway CPU and memory; port exhaustion often coincides with resource saturation
Port exhaustion is a capacity problem, not a configuration error. It typically emerges under sustained high load or with workloads that open many short-lived connections. Proper monitoring of connection state and port pool utilization will catch it before users do.