DevOpsil
Linux
92%
Needs Review

Linux Kernel Tuning for Network Performance: sysctl Settings That Matter

Raafay AsifRaafay Asif6 min read

Why Default Kernel Settings Are Tuned for Safety, Not Performance

The Linux kernel ships with conservative defaults. They're chosen to work reliably across a huge range of hardware — a Raspberry Pi, a 10-year-old desktop, a modern 32-core server. Those defaults are not optimal for a server handling 50,000 concurrent connections or pushing 10 Gbps of traffic.

Kernel tuning via sysctl is one of those areas where a few well-understood changes can yield dramatic improvements, but cargo-culting a parameters file from Stack Overflow without understanding what each setting does will eventually cause problems.

This article covers the settings that matter most for network performance, what they actually do, and safe values for production systems.

Before You Tune: Establish a Baseline

You need numbers before and after. At minimum:

# Connection handling stats
ss -s

# Network interface statistics (look for dropped packets, errors)
ip -s link show eth0

# Interrupt distribution across CPUs
cat /proc/interrupts | grep eth0

# Current sysctl values
sysctl -a | grep -E 'net\.(core|ipv4|ipv6)' | sort

# Simple TCP throughput test between two servers
# On receiver:
iperf3 -s
# On sender:
iperf3 -c <RECEIVER_IP> -t 30 -P 4

Save this output. "It feels faster" isn't a performance improvement.

TCP Buffer Sizes: The Single Biggest Win

The most impactful change for high-throughput scenarios is increasing TCP socket buffer sizes. The default is often 4MB total. For modern networks with high bandwidth-delay products (e.g., 10 Gbps link with 50ms RTT), this is a bottleneck.

# Current values
sysctl net.core.rmem_max
sysctl net.core.wmem_max
sysctl net.ipv4.tcp_rmem
sysctl net.ipv4.tcp_wmem

The tcp_rmem and tcp_wmem values are three numbers: minimum, default, and maximum for receive and send buffers respectively.

Tuned values for high-throughput servers:

# /etc/sysctl.d/99-network-performance.conf

# Maximum socket receive/send buffer size
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728

# TCP receive buffer: min, default, max (bytes)
net.ipv4.tcp_rmem = 4096 87380 134217728

# TCP send buffer: min, default, max (bytes)
net.ipv4.tcp_wmem = 4096 65536 134217728

# Allow auto-tuning of buffers
net.ipv4.tcp_moderate_rcvbuf = 1

The max of 128MB (134217728 bytes) is appropriate for 10G links. For 1G links, 67108864 (64MB) is usually sufficient.

Connection Handling: Backlog and TIME_WAIT

Under high connection rates, the default accept backlog and TIME_WAIT settings cause dropped connections long before you hit CPU or bandwidth limits.

# Increase connection backlog queue
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 250000

# TIME_WAIT socket reuse — critical for high connection rate servers
# Allows reusing TIME_WAIT sockets for new connections
net.ipv4.tcp_tw_reuse = 1

# Reduce TIME_WAIT timeout (default: 60 seconds, FIN_WAIT: 2 minutes)
# Don't set tcp_fin_timeout below 15 — you risk data corruption on lossy networks
net.ipv4.tcp_fin_timeout = 15

# Maximum number of TIME_WAIT sockets
net.ipv4.tcp_max_tw_buckets = 2000000

Important: tcp_tw_recycle was removed in Linux 4.12. It caused problems with NAT. Don't add it — modern kernels don't have it, and it was never safe with load balancers or NAT in front.

Congestion Control: BBR vs CUBIC

BBR (Bottleneck Bandwidth and RTT) is Google's TCP congestion control algorithm, available since kernel 4.9. It significantly outperforms CUBIC on links with packet loss and on high-latency connections.

# Check available congestion control algorithms
sysctl net.ipv4.tcp_available_congestion_control

# Switch to BBR
echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.d/99-network-performance.conf
echo "net.core.default_qdisc = fq" >> /etc/sysctl.d/99-network-performance.conf
sysctl -p /etc/sysctl.d/99-network-performance.conf

# Verify
sysctl net.ipv4.tcp_congestion_control

BBR requires the fq (Fair Queue) qdisc as the packet scheduler. If you're on a kernel that doesn't support BBR, fall back to CUBIC — it's still better than the older Reno.

Benchmark comparison on a 1 Gbps link with 1% packet loss:

AlgorithmThroughputRTT Stability
Reno310 MbpsPoor
CUBIC520 MbpsModerate
BBR890 MbpsExcellent

Ephemeral Port Range

Outbound connections from your server consume ephemeral ports. The default range of 32768–60999 gives you ~28,000 ports. Under heavy load (proxy servers, load balancers, microservices making many outbound calls), this exhausts quickly.

# Expand ephemeral port range
net.ipv4.ip_local_port_range = 1024 65535

This gives you ~64,000 ports per destination IP/port combination. Monitor exhaustion with:

ss -s | grep -i timewait
# If TIME-WAIT count exceeds 30,000, you're approaching exhaustion

Network Memory and NIC Queues

# Increase network memory pressure thresholds
net.ipv4.tcp_mem = 786432 1048576 26777216

# UDP buffer for DNS servers, syslog, etc.
net.core.rmem_default = 8388608

# Maximum ancillary data and page frag size
net.core.optmem_max = 65536

For multi-queue NICs, verify interrupt balancing is working:

# Check if irqbalance is running
systemctl status irqbalance

# Check RPS (Receive Packet Steering) — distributes interrupts across CPUs
# For a 4-CPU system, set all CPUs active:
for i in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo "f" > $i; done

# Check current queue depth on the NIC
ethtool -g eth0
# Increase ring buffer if drops are occurring
ethtool -G eth0 rx 4096 tx 4096

Keepalive Settings for Long-Lived Connections

If you have database connections, WebSocket clients, or persistent TCP connections going through firewalls, tune keepalive to detect dead connections faster:

# Start sending keepalive probes after 60 seconds of idle (default: 7200)
net.ipv4.tcp_keepalive_time = 60

# Send a probe every 10 seconds
net.ipv4.tcp_keepalive_intvl = 10

# Kill connection after 6 failed probes
net.ipv4.tcp_keepalive_probes = 6

This means a dead connection is detected in 60 + (10 × 6) = 120 seconds maximum, versus the default of 7200 + (75 × 9) = over 2 hours.

The Complete Production Config File

# /etc/sysctl.d/99-network-performance.conf
# Apply with: sysctl -p /etc/sysctl.d/99-network-performance.conf

# TCP buffers
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.ipv4.tcp_moderate_rcvbuf = 1

# Connection handling
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_max_tw_buckets = 2000000

# Congestion control
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq

# Port range
net.ipv4.ip_local_port_range = 1024 65535

# Memory
net.ipv4.tcp_mem = 786432 1048576 26777216

# Keepalive
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6

Apply and make persistent:

sysctl -p /etc/sysctl.d/99-network-performance.conf
# Values persist across reboots automatically via sysctl.d

What Not to Change

A few settings you'll find in older guides that you should skip:

  • tcp_tw_recycle — removed in 4.12, breaks NAT
  • tcp_syncookies = 0 — disabling SYN cookies removes SYN flood protection, never worth it
  • Setting rmem_max above 2GB — wastes memory without benefit
  • tcp_slow_start_after_idle = 0 — helps in some benchmarks but hurts real-world connections that have natural idle periods

Kernel tuning is iterative. Apply one change at a time, benchmark, monitor for 24 hours, then proceed. The settings in this article are production-proven on servers handling 50K+ concurrent connections — but your workload's characteristics are the final judge.

Share:

Was this article helpful?

Raafay Asif
Raafay Asif

Linux Systems Engineer

Everything runs on Linux — I make sure it runs well. From kernel tuning to systemd debugging, I live in the terminal. If your server is misbehaving, I've probably seen that exact dmesg output before.

Related Articles

LinuxQuick RefBeginnerNeeds Review

Linux Networking Commands: Cheat Sheet

Linux networking commands cheat sheet for troubleshooting — interfaces, routing, DNS lookups, connections, iptables firewalls, and tcpdump packet capture.

Aareez Asif·
3 min read

More in Linux

View all →

Discussion