Every Linux distribution ships with kernel parameters tuned for a generic use case. Ubuntu's defaults accommodate laptops and cloud VMs. RHEL's defaults balance server workloads against memory-constrained environments. These compromises make sense for general-purpose deployments — but on a Swiss dedicated server with 128GB of RAM, NVMe storage, and a 10Gbps network interface, those defaults are leaving substantial performance on the table.
The Linux kernel exposes thousands of tunable parameters through the sysctl interface. Most administrators never touch them, either because they don't know they exist or because the documentation is scattered across man pages, kernel source comments, and tribal knowledge. The result is bare metal hardware running at a fraction of its potential — network buffers sized for 1990s bandwidth, memory management tuned for systems with megabytes instead of gigabytes, and I/O schedulers designed for spinning rust instead of NVMe.
This guide walks through the kernel parameters that actually matter for high-performance dedicated server workloads. No cargo-culting from Stack Overflow posts. No copying values without understanding what they do. Each parameter includes the why, the what, and the specific scenarios where tuning makes a measurable difference.
Optimization without measurement is guesswork. Before changing any kernel parameters, capture baseline metrics for your actual workload. This gives you before-and-after comparisons and helps identify whether a change improved things, made them worse, or had no effect at all.
# Network baseline: throughput and latency
iperf3 -c target-ip -t 60 -P 4 --json > /tmp/baseline-network.json
# Storage baseline: random read IOPS and latency
fio --name=baseline --ioengine=libaio --direct=1 --bs=4k \
--iodepth=64 --size=4G --rw=randread --runtime=60 \
--time_based --output-format=json > /tmp/baseline-storage.json
# Memory baseline: allocation and page fault rates
vmstat 1 60 > /tmp/baseline-vmstat.txt
# CPU baseline: context switches and interrupts
sar -w 1 60 > /tmp/baseline-cpu.txt
# Current sysctl values (save before modifying)
sysctl -a > /tmp/baseline-sysctl.txt
Run your application under realistic load during baseline capture. The metrics that matter are those under production-like conditions, not idle system stats. If you're tuning a database server, run a representative query workload. If you're tuning a web server, generate traffic that matches your real traffic patterns.
The Linux network stack is designed to work across everything from embedded devices to 400Gbps data center switches. Default parameters assume low-end hardware and conservative memory usage. On a dedicated server with abundant RAM and high-bandwidth interfaces, these defaults create artificial bottlenecks.
TCP buffer sizes. TCP performance depends on having buffers large enough to keep the connection saturated during round-trip latency. The bandwidth-delay product formula (BDP = bandwidth × RTT) determines the minimum buffer size needed. For a 10Gbps link with 10ms RTT to a European peer, BDP = 10,000,000,000 bits/sec × 0.01 sec = 100,000,000 bits = 12.5MB. The default Linux TCP buffer sizes are nowhere near this:
# Check current TCP buffer settings
sysctl net.core.rmem_max net.core.wmem_max
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem
# Typical defaults:
# net.core.rmem_max = 212992 (208KB)
# net.core.wmem_max = 212992 (208KB)
# net.ipv4.tcp_rmem = 4096 131072 6291456 (min default max)
# net.ipv4.tcp_wmem = 4096 16384 4194304
# Optimized settings for 10Gbps with 10-50ms RTT
sysctl -w net.core.rmem_max=67108864
sysctl -w net.core.wmem_max=67108864
sysctl -w net.core.rmem_default=1048576
sysctl -w net.core.wmem_default=1048576
sysctl -w net.ipv4.tcp_rmem="4096 1048576 67108864"
sysctl -w net.ipv4.tcp_wmem="4096 1048576 67108864"
sysctl -w net.ipv4.tcp_mem="786432 1048576 26777216"
The tcp_rmem and tcp_wmem parameters take three values: minimum, default, and maximum. The kernel auto-tunes within this range based on available memory and connection requirements. Setting a high maximum allows the kernel to allocate large buffers for high-BDP connections while keeping memory usage reasonable for small transfers.
Connection backlog and queue sizes. When traffic spikes hit your server, connection handling capacity becomes the bottleneck before CPU or bandwidth. The kernel queues incoming connections in the listen backlog and processes them as fast as the application can accept(). Default queue sizes are woefully inadequate for high-traffic servers:
# Increase listen backlog for high-connection-rate applications
sysctl -w net.core.somaxconn=65535
sysctl -w net.core.netdev_max_backlog=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
# Reduce TIME_WAIT accumulation (careful with NAT scenarios)
sysctl -w net.ipv4.tcp_fin_timeout=15
sysctl -w net.ipv4.tcp_tw_reuse=1
# Enable TCP Fast Open (reduces connection latency)
sysctl -w net.ipv4.tcp_fastopen=3
# Increase ephemeral port range for outbound connections
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
TCP congestion control. The default congestion control algorithm (Cubic on most distributions) is designed for general-purpose fairness. For dedicated servers with high-bandwidth paths, BBR (Bottleneck Bandwidth and Round-trip propagation time) often delivers superior throughput by measuring actual network capacity rather than reacting to packet loss:
# Check available congestion control algorithms
sysctl net.ipv4.tcp_available_congestion_control
# Enable BBR (requires kernel 4.9+ with BBR compiled in)
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr
# Verify BBR is active
sysctl net.ipv4.tcp_congestion_control
# Should return: net.ipv4.tcp_congestion_control = bbr
BBR particularly shines on long-distance connections (transatlantic, transcontinental) where traditional loss-based algorithms underutilize available bandwidth. For servers handling international traffic from Swiss data centers, BBR can improve throughput to distant clients by 30-50% compared to Cubic.
Linux memory management is sophisticated and largely self-tuning, but the heuristics assume generic workloads. Database servers, caching layers, and high-throughput applications benefit from explicit tuning that matches their memory access patterns.
Virtual memory behavior. The vm.swappiness parameter controls how aggressively the kernel moves memory pages to swap. On servers with abundant RAM and SSDs, aggressive swapping is counterproductive — disk I/O, even on NVMe, is orders of magnitude slower than RAM access:
# Check current swappiness (default is 60)
sysctl vm.swappiness
# For dedicated servers with ample RAM (64GB+)
# Keep as much in RAM as possible
sysctl -w vm.swappiness=10
# For pure in-memory workloads (Redis, Memcached)
# Only swap when absolutely necessary
sysctl -w vm.swappiness=1
# Reduce tendency to swap out VFS cache
sysctl -w vm.vfs_cache_pressure=50
Dirty page management. When applications write data, the kernel buffers those writes in page cache before flushing to disk. The dirty page parameters control when and how aggressively this flushing occurs. Defaults are conservative for systems with limited RAM:
# Check current dirty page settings
sysctl vm.dirty_ratio vm.dirty_background_ratio
# Default: dirty_ratio=20, dirty_background_ratio=10
# Meaning: start background writeback at 10% of RAM dirty,
# block writers at 20% dirty
# For servers with fast storage (NVMe) and lots of RAM
# Allow more dirty pages before blocking writers
sysctl -w vm.dirty_ratio=40
sysctl -w vm.dirty_background_ratio=10
# For database servers: tighter control over dirty pages
# More frequent, smaller flushes reduce checkpoint spikes
sysctl -w vm.dirty_ratio=15
sysctl -w vm.dirty_background_ratio=3
sysctl -w vm.dirty_expire_centisecs=500
sysctl -w vm.dirty_writeback_centisecs=100
Transparent Huge Pages. THP automatically promotes small pages (4KB) to huge pages (2MB) to reduce TLB misses. This is beneficial for some workloads (large sequential memory access) and harmful for others (databases with random access patterns, Redis). Most database vendors recommend disabling THP:
# Check THP status
cat /sys/kernel/mm/transparent_hugepage/enabled
# Disable THP for database workloads
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# Make persistent (add to /etc/rc.local or systemd unit)
# Or via GRUB: add "transparent_hugepage=never" to kernel cmdline
NUMA awareness. Multi-socket servers (dual Xeon, dual EPYC) have Non-Uniform Memory Access architecture. Memory attached to CPU0 is faster for CPU0 to access than memory attached to CPU1. The kernel can be tuned to prefer local memory allocation:
# Check NUMA topology
numactl --hardware
# View current NUMA policy
cat /proc/sys/vm/zone_reclaim_mode
# For most workloads: allow cross-NUMA allocation
# (prevents memory starvation on one node)
sysctl -w vm.zone_reclaim_mode=0
# For latency-sensitive workloads: prefer local, reclaim before going remote
sysctl -w vm.zone_reclaim_mode=1
Storage is typically the biggest bottleneck in server performance. Even fast NVMe drives benefit from kernel tuning that matches the device characteristics and workload patterns.
I/O schedulers. The kernel I/O scheduler reorders and merges disk requests to optimize throughput. The right scheduler depends on your storage type and workload:
# Check current scheduler for NVMe device
cat /sys/block/nvme0n1/queue/scheduler
# Available schedulers (modern kernels):
# [mq-deadline] kyber bfq none
# For NVMe SSDs: 'none' or 'mq-deadline'
# NVMe has internal queuing, kernel scheduler adds latency
echo none > /sys/block/nvme0n1/queue/scheduler
# For SATA SSDs: 'mq-deadline' or 'bfq'
echo mq-deadline > /sys/block/sda/queue/scheduler
# For spinning disks: 'bfq' (budget fair queueing)
echo bfq > /sys/block/sdb/queue/scheduler
# Make persistent via udev rule
# /etc/udev/rules.d/60-ioscheduler.rules
# ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"
# ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
Queue depth and nr_requests. NVMe devices can handle thousands of concurrent I/O operations. The kernel queue depth should be high enough to keep the device saturated:
# Check current queue depth
cat /sys/block/nvme0n1/queue/nr_requests
# For high-IOPS NVMe (typical default is 1024, which is usually fine)
# Increase if fio benchmarks show queue depth limiting IOPS
echo 2048 > /sys/block/nvme0n1/queue/nr_requests
# Check if read-ahead is appropriate for your workload
cat /sys/block/nvme0n1/queue/read_ahead_kb
# For random I/O workloads (databases): reduce read-ahead
echo 8 > /sys/block/nvme0n1/queue/read_ahead_kb
# For sequential I/O (video streaming, backups): increase read-ahead
echo 2048 > /sys/block/nvme0n1/queue/read_ahead_kb
Filesystem tuning. The choice of filesystem and its mount options significantly impact performance. For most high-performance workloads on modern hardware, XFS or ext4 with appropriate options:
# XFS mount options for high-performance
# /etc/fstab entry:
# /dev/nvme0n1p1 /data xfs defaults,noatime,nodiratime,logbufs=8,logbsize=256k 0 2
# ext4 mount options for high-performance
# /dev/nvme0n1p1 /data ext4 defaults,noatime,nodiratime,data=writeback,barrier=0,nobh 0 2
# WARNING: data=writeback and barrier=0 risk data loss on power failure
# Only use with UPS + server-grade hardware with power-loss protection
# Verify mount options
mount | grep /data
# For databases: check filesystem alignment with storage
blockdev --getalignoff /dev/nvme0n1
# Should return 0 (properly aligned)
High-throughput network and storage workloads generate millions of interrupts per second. How those interrupts are distributed across CPU cores significantly impacts latency and throughput.
IRQ balancing. By default, irqbalance distributes interrupts across cores. For high-performance scenarios, pinning interrupts to specific cores can reduce cache misses and improve locality:
# View current interrupt distribution
cat /proc/interrupts | head -20
# Check which CPU handles each NVMe queue
cat /proc/interrupts | grep nvme
# Disable irqbalance for manual control
systemctl stop irqbalance
systemctl disable irqbalance
# Pin NVMe interrupts to specific cores
# Find NVMe IRQ numbers
grep nvme /proc/interrupts | awk '{print $1}' | tr -d ':'
# Set affinity for IRQ 45 to CPU 0
echo 1 > /proc/irq/45/smp_affinity
# For network interfaces: use RPS/RFS instead of manual pinning
# Receive Packet Steering spreads load across cores
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
# (f = cores 0-3 in hex bitmap)
# Enable Receive Flow Steering for connection locality
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
CPU frequency scaling. Modern CPUs adjust frequency based on load (P-states) and can enter deep sleep states (C-states) during idle periods. For latency-sensitive workloads, these power-saving features introduce jitter:
# Check current CPU governor
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# For latency-sensitive workloads: lock to max frequency
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# Alternatively, via cpupower
cpupower frequency-set -g performance
# Disable deep C-states via kernel parameter (GRUB)
# intel_idle.max_cstate=1 processor.max_cstate=1
# Verify current frequency
grep -E '^cpu MHz' /proc/cpuinfo
Some kernel security features carry measurable performance costs. On dedicated hardware where you control all workloads (no untrusted tenants), selectively disabling these features can recover performance — but understand the risks.
Spectre/Meltdown mitigations. CPU vulnerability mitigations (IBRS, IBPB, STIBP, PTI) can cost 5-30% performance depending on workload. On a Swiss dedicated server where you're the only tenant, the side-channel attack surface is dramatically reduced:
# Check current mitigation status
cat /sys/devices/system/cpu/vulnerabilities/*
# View performance impact of mitigations
grep -E 'Mitigation|Vulnerable' /sys/devices/system/cpu/vulnerabilities/*
# Disable mitigations (kernel parameter in GRUB)
# WARNING: Only appropriate on single-tenant dedicated hardware
# mitigations=off
# Or selective disabling:
# spectre_v2=off nopti spec_store_bypass_disable=off
# After reboot, verify
dmesg | grep -i spectre
dmesg | grep -i meltdown
Kernel Address Space Layout Randomization. KASLR randomizes kernel memory layout to make exploits harder. The performance impact is minimal on modern hardware, so there's rarely a reason to disable it:
# Check KASLR status
cat /proc/cmdline | grep -o 'nokaslr\|kaslr' || echo "KASLR enabled (default)"
# Leave KASLR enabled unless debugging kernel issues
# The performance cost is negligible
Here's a complete sysctl configuration for a high-performance Swiss dedicated server running typical workloads (web serving, databases, application hosting). Adjust values based on your specific hardware and applications:
# /etc/sysctl.d/99-high-performance.conf
# High-performance kernel tuning for dedicated servers
# ============================================
# NETWORK STACK
# ============================================
# TCP buffer sizes (for 10Gbps, adjust for your bandwidth)
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
net.ipv4.tcp_rmem = 4096 1048576 67108864
net.ipv4.tcp_wmem = 4096 1048576 67108864
net.ipv4.tcp_mem = 786432 1048576 26777216
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192
# Connection handling
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_max_tw_buckets = 2000000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# TCP performance
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
# Congestion control (BBR)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# Port range for outbound connections
net.ipv4.ip_local_port_range = 1024 65535
# ============================================
# MEMORY MANAGEMENT
# ============================================
# Swappiness (low for servers with ample RAM)
vm.swappiness = 10
vm.vfs_cache_pressure = 50
# Dirty page handling (tune based on storage and workload)
vm.dirty_ratio = 30
vm.dirty_background_ratio = 5
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
# Memory overcommit (depends on workload)
vm.overcommit_memory = 0
vm.overcommit_ratio = 80
# Maximum map count (for Elasticsearch, MongoDB, etc.)
vm.max_map_count = 262144
# ============================================
# FILESYSTEM
# ============================================
# Increase file descriptor limits
fs.file-max = 2097152
fs.nr_open = 2097152
# Increase inotify limits (for applications watching many files)
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512
# ============================================
# KERNEL SECURITY (adjust based on threat model)
# ============================================
# Prevent SYN floods
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_orphans = 262144
# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Enable reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# ============================================
# PROCESS LIMITS
# ============================================
# Increase PID limit for containerized workloads
kernel.pid_max = 4194304
# Increase message queue limits
kernel.msgmnb = 65536
kernel.msgmax = 65536
Apply the configuration:
# Apply sysctl changes
sysctl -p /etc/sysctl.d/99-high-performance.conf
# Verify key settings
sysctl net.ipv4.tcp_congestion_control
sysctl vm.swappiness
sysctl net.core.somaxconn
Different applications benefit from different tuning emphases. Here are adjustments for common workloads:
Database servers (PostgreSQL, MySQL):
# Lower swappiness — databases manage their own caching
vm.swappiness = 1
# Tighter dirty page control — more predictable checkpoint behavior
vm.dirty_ratio = 10
vm.dirty_background_ratio = 3
vm.dirty_expire_centisecs = 500
vm.dirty_writeback_centisecs = 100
# Disable THP (causes latency spikes)
# Add to /etc/rc.local or systemd service:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# Increase shared memory limits for large buffer pools
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
Web servers and reverse proxies (Nginx, HAProxy):
# Maximize connection handling capacity
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# Aggressive TIME_WAIT handling for high-connection-rate proxies
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10
# Increase file descriptors (one per connection)
fs.file-max = 2097152
# Enable TCP Fast Open for connection latency reduction
net.ipv4.tcp_fastopen = 3
In-memory caching (Redis, Memcached):
# Never swap — all data is in RAM
vm.swappiness = 0
vm.overcommit_memory = 1
# Disable THP (critical for Redis)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# Large buffer for persistence writes (Redis RDB/AOF)
vm.dirty_background_ratio = 5
vm.dirty_ratio = 60
High-throughput file serving and media streaming:
# Large read-ahead for sequential access
echo 2048 > /sys/block/nvme0n1/queue/read_ahead_kb
# Increase socket buffers for video streaming
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
# Allow more dirty pages (batch writes to storage)
vm.dirty_ratio = 50
vm.dirty_background_ratio = 10
After applying tuning changes, validate that they actually improved your metrics. Run the same baseline tests from earlier and compare:
# Compare network throughput
iperf3 -c target-ip -t 60 -P 4 --json > /tmp/tuned-network.json
# Compare storage performance
fio --name=tuned --ioengine=libaio --direct=1 --bs=4k \
--iodepth=64 --size=4G --rw=randread --runtime=60 \
--time_based --output-format=json > /tmp/tuned-storage.json
# Quick diff of key metrics
jq '.end.sum_received.bits_per_second' /tmp/baseline-network.json /tmp/tuned-network.json
jq '.jobs[0].read.iops' /tmp/baseline-storage.json /tmp/tuned-storage.json
# Monitor ongoing with sar
sar -n DEV 1 60 # Network interface stats
sar -d 1 60 # Disk I/O stats
sar -r 1 60 # Memory utilization
Watch for regressions. Occasionally, tuning for one metric hurts another. If you increase network buffers dramatically, memory pressure might increase. If you disable power saving, electricity costs go up. Kernel tuning is always a series of trade-offs — optimize for what matters most to your specific workload.
Kernel parameters reset on reboot unless persisted properly. Here's how to make your tuning durable:
# sysctl persistence
# Place configuration in /etc/sysctl.d/99-high-performance.conf
# (as shown above)
# I/O scheduler persistence via udev
# /etc/udev/rules.d/60-ioscheduler.rules
ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# THP disabling via systemd
# /etc/systemd/system/disable-thp.service
[Unit]
Description=Disable Transparent Huge Pages
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=basic.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install]
WantedBy=basic.target
# Enable the service
systemctl enable disable-thp.service
# GRUB parameters for kernel command line options
# Edit /etc/default/grub:
GRUB_CMDLINE_LINUX="intel_idle.max_cstate=1 processor.max_cstate=1"
# Then: update-grub && reboot
Kernel tuning can unlock 20-50% performance improvements for many workloads. But there are limits. If your baseline metrics show:
• CPU saturation: All cores at 100% — you need more cores or a faster processor
• Memory exhaustion: Swapping despite low swappiness — you need more RAM
• Storage IOPS ceiling: NVMe fully saturated — you need faster storage or a different architecture (caching, distributed storage)
• Network bandwidth saturation: Interface at 100% — you need a faster NIC or multiple NICs
No amount of sysctl tuning fixes hardware limitations. If your Swiss VPS has hit its ceiling, graduating to a dedicated server with appropriate specs is the next step. If your dedicated server is maxed, look at extreme bandwidth servers or distributed architectures.
Linux kernel tuning is not magic — it's the systematic process of aligning kernel behavior with your hardware capabilities and workload characteristics. Default parameters assume generic hardware and conservative resource usage. On a properly-specced dedicated server, those defaults leave substantial performance on the table.
The parameters that matter most are:
• Network buffers: Sized for your bandwidth-delay product
• Connection queues: Scaled for your connection rates
• TCP congestion control: BBR for high-bandwidth paths
• Memory management: Swappiness and dirty pages tuned for your workload
• I/O scheduling: Matched to your storage type
Start with baseline measurements. Apply changes incrementally. Validate each change against your actual workload metrics. Make the tuning persistent. And remember that kernel tuning is maintenance, not a one-time event — as kernels evolve and workloads change, your tuning should evolve with them.
For those running high-performance workloads on Swiss infrastructure, these optimizations help ensure you're extracting full value from the hardware. The silicon is capable. The network is fast. The only question is whether the software is configured to use what's available.