Basic sysctl Usage
sysctl is an interface for reading and writing kernel parameters while the kernel is running.
# Query the current value
sysctl net.core.somaxconn
sysctl -a | grep tcp_tw # Pattern search
# Apply immediately (resets on reboot)
sudo sysctl -w net.core.somaxconn=65535
# Persist across reboots (/etc/sysctl.d/99-tuning.conf)
echo "net.core.somaxconn = 65535" | sudo tee -a /etc/sysctl.d/99-tuning.conf
sudo sysctl -p /etc/sysctl.d/99-tuning.conf
# Reload all settings
sudo sysctl --systemParameters can also be accessed directly via the /proc/sys/ path. net.core.somaxconn = /proc/sys/net/core/somaxconn
1. Network Stack Tuning
TCP Connection Handling Limits
# /etc/sysctl.d/99-network.conf
# SYN backlog queue size (prevents SYN drops under high concurrent connections)
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# Network device input queue size
net.core.netdev_max_backlog = 65535
# Expand the local port range (when there are many outbound connections)
net.ipv4.ip_local_port_range = 1024 65535TIME_WAIT Socket Reuse
Under a large volume of short-lived connections (HTTP/1.1 polling, microservice internal communication), TIME_WAIT sockets can exhaust available ports.
# Allow reuse of sockets in TIME_WAIT (client side)
net.ipv4.tcp_tw_reuse = 1
# Shorten the FIN_WAIT2 timeout (default 60s → 15s)
net.ipv4.tcp_fin_timeout = 15
# Maximum number of TIME_WAIT buckets (saves memory)
net.ipv4.tcp_max_tw_buckets = 1440000# Check the current socket state distribution
ss -s
# Monitor the TIME_WAIT count in real time
watch -n1 "ss -s | grep TIME-WAIT"TCP Buffer Sizes — Throughput Optimization
In high-bandwidth (1 Gbps+) environments, small buffers constrain TCP window scaling and reduce throughput.
# TCP socket read/write buffers (min / default / max, bytes)
net.core.rmem_default = 262144
net.core.rmem_max = 134217728 # 128MB
net.core.wmem_default = 262144
net.core.wmem_max = 134217728
# TCP auto-tuning range (min / pressure / max)
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
# Enable automatic buffer tuning
net.ipv4.tcp_moderate_rcvbuf = 1
# BBR congestion control algorithm (Linux 4.9+; outperforms CUBIC in high-RTT environments)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr# Check whether BBR is supported
sysctl net.ipv4.tcp_available_congestion_control
# Current congestion control algorithm
sysctl net.ipv4.tcp_congestion_control
# Measure TCP throughput (iperf3)
iperf3 -c TARGET_HOST -t 30 -P 4Keepalive — Clearing Zombie Connections
# Idle time before starting keepalive probes (default 7200s → 60s)
net.ipv4.tcp_keepalive_time = 60
# Interval between probe retries
net.ipv4.tcp_keepalive_intvl = 10
# Maximum number of probes (connection is dropped if exceeded)
net.ipv4.tcp_keepalive_probes = 62. File Descriptor and inotify Limits
Causes of and remedies for the "Too many open files" error on high-traffic servers.
# /etc/sysctl.d/99-fs.conf
# System-wide maximum number of file handles
fs.file-max = 2097152
# inotify watcher limits (Kafka, Elasticsearch, Docker environments)
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512
# AIO limit (database I/O)
fs.aio-max-nr = 1048576# /etc/security/limits.d/99-nofile.conf (per-process limits)
* soft nofile 1048576
* hard nofile 1048576
root soft nofile 1048576
root hard nofile 1048576# Currently used file handles / maximum
cat /proc/sys/fs/file-nr # allocated / unused / maximum
# Number of open files for a specific process
ls /proc/1234/fd | wc -l
# Top 10 processes by file-handle usage system-wide
lsof 2>/dev/null | awk '{print $1}' | sort | uniq -c | sort -rn | head 103. Memory Management Tuning
vm.swappiness — Swap Tendency
# /etc/sysctl.d/99-memory.conf
# Swap aggressiveness (0 = minimize swap, 100 = use aggressively)
# Database servers: 1–10 recommended (protects the memory cache)
# General-purpose servers: 10–30
vm.swappiness = 10
# Dirty page ratio limits (prevents I/O bursts)
vm.dirty_ratio = 10 # Force flush when dirty pages exceed 10% of total memory
vm.dirty_background_ratio = 5 # Start background flush when dirty pages exceed 5%
# Maximum time dirty pages are kept (100 cs = 1 second)
vm.dirty_expire_centisecs = 3000 # 30 seconds
vm.dirty_writeback_centisecs = 500 # Wake the flush thread every 5 seconds# Current dirty page status
cat /proc/meminfo | grep -i dirty
# Force a dirty-page flush (caution: causes an I/O spike)
sync; echo 3 | sudo tee /proc/sys/vm/drop_cachesControlling the OOM Killer
# Check OOM score (higher = killed first; -1000 = never kill)
cat /proc/1234/oom_score
cat /proc/1234/oom_score_adj
# Protect a critical process from OOM (PostgreSQL example)
echo -500 | sudo tee /proc/$(pgrep -f "postgres: checkpointer")/oom_score_adj
# Set OOM policy at the systemd service unit level
# /etc/systemd/system/postgresql.service.d/override.conf
[Service]
OOMScoreAdjust=-500# Kill a process without panicking on OOM (keeping the default is recommended)
vm.panic_on_oom = 0
vm.oom_kill_allocating_task = 0HugePages — Optimizing Large-Memory Databases
Processes that use large amounts of memory—such as PostgreSQL, Oracle, and Redis—can reduce TLB misses with HugePages.
# Current HugePage usage
grep -i huge /proc/meminfo
# Calculate the required number of HugePages (based on PostgreSQL shared_buffers)
# shared_buffers = 8GB, HugePage = 2MB
# Required count = 8 * 1024 / 2 = 4096
# Set the number of HugePages
echo "vm.nr_hugepages = 4096" | sudo tee -a /etc/sysctl.d/99-hugepages.conf
sudo sysctl -p /etc/sysctl.d/99-hugepages.conf
# Enable HugePages in PostgreSQL
# postgresql.conf: huge_pages = on4. cgroups v2 — Resource Isolation
cgroups v2 lets you precisely limit CPU, memory, and I/O per process or container.
# Check whether cgroups v2 is mounted
mount | grep cgroup2
# or
stat -fc %T /sys/fs/cgroup/
# Inspect the current cgroup hierarchy
systemctl status --no-pager | head -5
cat /proc/1234/cgroupLimiting Service Resources with systemd
# /etc/systemd/system/myapp.service.d/limits.conf
[Service]
# CPU: equivalent of 2 cores max (200%)
CPUQuota=200%
# Memory: 4 GB max (OOM-killed if exceeded)
MemoryMax=4G
MemorySwapMax=0 # Disable swap
# I/O: limit read/write to 100 MB/s each
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 100M
# Limit the number of processes
TasksMax=512sudo systemctl daemon-reload
sudo systemctl restart myapp
# Check live resource usage
systemctl status myapp | grep -E "Memory|CPU|Tasks"
# Inspect cgroup stats directly
cat /sys/fs/cgroup/system.slice/myapp.service/memory.current
cat /sys/fs/cgroup/system.slice/myapp.service/cpu.statManually Creating a cgroup and Assigning Processes
# Create a cgroup
sudo mkdir /sys/fs/cgroup/batch-jobs
# Set CPU weight (default 100; lower = lower priority)
echo 20 | sudo tee /sys/fs/cgroup/batch-jobs/cpu.weight
# Set a memory limit
echo $((2 * 1024 * 1024 * 1024)) | sudo tee /sys/fs/cgroup/batch-jobs/memory.max
# Place a process
echo $BASHPID | sudo tee /sys/fs/cgroup/batch-jobs/cgroup.procs
# Run a batch job (inside this cgroup)
./heavy-batch-job.sh5. NUMA Architecture Optimization
On multi-socket servers, ignoring NUMA topology causes cross-node memory access and a sharp increase in latency.
# Inspect NUMA topology
numactl --hardware
numastat
# Pin a process to a specific NUMA node
numactl --cpunodebind=0 --membind=0 ./my-program
# Pin PostgreSQL to NUMA node 0
numactl --cpunodebind=0 --membind=0 -u postgres pg_ctl start
# Disable NUMA automatic balancing (recommended for DB servers)
echo 0 | sudo tee /proc/sys/kernel/numa_balancing6. Recommended Profiles by Workload
High-Traffic Web Server (Nginx / HAProxy)
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
fs.file-max = 2097152Database Server (PostgreSQL / MySQL)
vm.swappiness = 1
vm.dirty_ratio = 5
vm.dirty_background_ratio = 2
vm.nr_hugepages = 4096 # Adjust to match shared_buffers size
kernel.numa_balancing = 0
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6
fs.aio-max-nr = 1048576Container Host (Docker / Kubernetes)
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512
vm.max_map_count = 262144 # Required for Elasticsearch
net.bridge.bridge-nf-call-iptables = 1 # Kubernetes CNI
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
kernel.pid_max = 4194304# Verify settings — dump current values after applying
for param in net.core.somaxconn vm.swappiness fs.file-max vm.nr_hugepages; do
echo "$param = $(sysctl -n $param)"
doneAI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us
Questions & answers
Ask a question about this guide. We'll review and reply.