How to Tune Kernel Parameters with sysctl
Learn how to tune Linux kernel parameters at runtime and permanently using sysctl and /etc/sysctl.d, with practical network and VM tunables explained.
Before you start
- ▸Root or sudo access on the target system
- ▸Basic familiarity with Linux file editing and the terminal
- ▸Kernel 4.9 or later for BBR congestion control support
- ▸Understanding of the workload profile you are tuning for
The Linux kernel exposes hundreds of runtime parameters through the /proc/sys virtual filesystem. sysctl is the standard interface for reading and writing those parameters without rebooting. Knowing which knobs matter—and how to make changes survive a reboot—is essential for squeezing performance out of servers, tuning network stacks, and hardening systems. This guide covers the mechanics, the persistence layer at /etc/sysctl.d/, and a curated set of network and VM tunables worth understanding in production.
How sysctl Works
Every file under /proc/sys maps to a kernel parameter. The dotted names sysctl uses simply replace directory separators with dots: net.ipv4.tcp_rmem maps to /proc/sys/net/ipv4/tcp_rmem. You can read and write those files directly with cat and echo, but sysctl is safer and handles persistence hooks properly.
Read a Single Parameter
sysctl net.ipv4.tcp_rmem
Read All Current Parameters
sysctl -a
Output will be several hundred lines and varies by kernel version and loaded modules.
Write a Parameter at Runtime
sysctl -w net.core.somaxconn=4096
This takes effect immediately but is lost on reboot. Runtime writes are useful for testing before committing to a config file.
Making Changes Persistent with /etc/sysctl.d/
Drop .conf files into /etc/sysctl.d/ rather than editing /etc/sysctl.conf directly. Files are read in lexicographic order, so prefix your files with a number (e.g., 90-network-tuning.conf) to control precedence. Distro packages typically ship their own files in this directory, and yours should come after them so they win.
Create a Tuning File
sudo tee /etc/sysctl.d/90-tuning.conf <<'EOF'
# Network performance
net.core.somaxconn = 4096
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_slow_start_after_idle = 0
# VM / memory
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
vm.overcommit_memory = 1
# Security / hardening
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.tcp_syncookies = 1
EOF
Apply Without Rebooting
sudo sysctl --system
--system reads all files from /etc/sysctl.d/, /run/sysctl.d/, /usr/lib/sysctl.d/, and /etc/sysctl.conf in the correct order. It is the modern replacement for sysctl -p.
Key Network Tunables Explained
Socket Backlog: net.core.somaxconn
Controls the maximum length of the accept queue for listening sockets. The kernel default is 4096 on recent kernels, but older distros ship 128 or 512. Under heavy inbound connection load (reverse proxies, web servers) this queue filling up causes silent connection drops. Set to 4096 or higher and ensure your application calls listen() with a matching backlog.
TCP Buffer Sizes: tcp_rmem / tcp_wmem
These three-value triplets define minimum, default, and maximum socket buffer sizes in bytes for receive and send paths respectively. The maximum should match net.core.rmem_max / net.core.wmem_max—the kernel silently clamps to those ceilings. For high-bandwidth paths (10 Gbps+) or high-latency links (satellite, intercontinental), larger buffers allow the TCP window to fill the bandwidth-delay product.
Congestion Control: tcp_congestion_control + default_qdisc
BBR (Bottleneck Bandwidth and Round-trip propagation time) is Google's congestion control algorithm, available since kernel 4.9 and enabled by loading the tcp_bbr module. Pair it with the fq (Fair Queuing) qdisc for best results. Check that the module is loaded before setting this parameter:
modprobe tcp_bbr
echo tcp_bbr | sudo tee /etc/modules-load.d/tcp_bbr.conf
TCP Fast Open: tcp_fastopen
Value 3 enables TFO for both clients and servers. TFO allows data to be sent in the SYN packet for repeat connections, cutting one round-trip from connection establishment. Requires application-level support (nginx, for example, supports it). Value 1 is client-only, 2 is server-only.
tcp_slow_start_after_idle
When set to 0, the kernel does not reset the TCP congestion window after a connection goes idle. This is a meaningful improvement for persistent connections that burst traffic periodically (keep-alive HTTP, replication streams).
Key VM Tunables Explained
vm.swappiness
A value from 0 to 200 (kernel ≥ 5.8) or 0 to 100 on older kernels. It biases the reclaim balance between anonymous memory (swap candidate) and page cache. 10 strongly prefers evicting page cache over swapping out application memory. Use 1 on database hosts where unexpected swap latency is catastrophic. Do not set it to 0 on kernels before 3.5—that prevented swapping entirely and could cause OOM kills.
vm.dirty_ratio / vm.dirty_background_ratio
dirty_background_ratio is the percentage of total memory at which the kernel starts writing dirty pages in the background. dirty_ratio is the hard cap at which processes block on writes. Lowering both reduces the worst-case write-back burst at the cost of more frequent I/O—good for spinning disks and latency-sensitive workloads. For write-heavy workloads on NVMe, you can raise these slightly.
vm.overcommit_memory
Mode 1 always allows overcommit, which is what Redis, some JVMs, and fork-heavy workloads expect. Mode 0 (default) uses heuristic checking. Mode 2 refuses any overcommit—rarely useful outside strict environments.
Distro-Specific Notes
Debian / Ubuntu
# Apply immediately and verify
sudo sysctl --system
sysctl net.core.somaxconn
Fedora / RHEL / Rocky
RHEL 9 and Rocky 9 ship with a /usr/lib/sysctl.d/50-default.conf that sets several security defaults. Your files in /etc/sysctl.d/ with a higher numeric prefix will override them correctly.
sudo sysctl --system
# Confirm precedence
sysctl -a 2>/dev/null | grep rp_filter
Arch Linux
Arch ships almost no default sysctl overrides, so you start with bare kernel defaults. The systemd-sysctl.service unit applies your files at boot—no extra steps needed.
sudo systemctl status systemd-sysctl.service
Verification
After applying, confirm each critical value loaded correctly:
sysctl net.core.somaxconn net.ipv4.tcp_congestion_control vm.swappiness
Expected output (will vary if you used different values):
net.core.somaxconn = 4096
net.ipv4.tcp_congestion_control = bbr
vm.swappiness = 10
To confirm changes survive reboot, restart and re-run the same command. You can also use sysctl --system --dry-run (kernel ≥ 5.2) to preview what would be applied without writing anything.
Troubleshooting
Parameter is read-only or not found
Some parameters only exist when a specific kernel module is loaded. If net.ipv4.tcp_congestion_control = bbr fails, tcp_bbr is not loaded. Run modprobe tcp_bbr and retry. Parameters under /proc/sys/net/bridge/ require br_netfilter.
Value reverts after applying --system
A later file in the load order is overriding yours. Run sysctl --system 2>&1 | grep <parameter> to see which file wins. Rename your file to a higher number (e.g., 99-) to take precedence, but be aware that some security frameworks (SELinux policy, systemd-networkd) may re-apply their own values after boot via separate mechanisms.
BBR not available on older kernels
BBR requires kernel 4.9+. Ubuntu 18.04 LTS (kernel 4.15) and later, Fedora 26+, and Arch all have it. RHEL 7 uses a 3.10 kernel and does not support BBR without a custom kernel. Check with uname -r and sysctl net.ipv4.tcp_available_congestion_control.
Changes not applied at boot (non-systemd edge case)
On all modern distros with systemd, systemd-sysctl.service handles this. Verify it is enabled:
systemctl is-enabled systemd-sysctl.service
It should print static—this unit is a dependency of sysinit.target and cannot be disabled through normal means.
Frequently asked questions
- What is the difference between /etc/sysctl.conf and /etc/sysctl.d/?
- /etc/sysctl.conf is the legacy single config file. /etc/sysctl.d/ allows modular, ordered configuration drop-ins. Distro packages and tools use sysctl.d so their values can be overridden cleanly without editing the base file. Prefer sysctl.d for all new configuration.
- Will these changes survive a kernel upgrade?
- Yes. Sysctl parameters are kernel-version-agnostic plain text files. The only risk is a new kernel version removing or renaming a parameter, which would cause systemd-sysctl to log a warning but not fail boot.
- Is it safe to set vm.overcommit_memory=1 in production?
- It depends on the workload. Redis explicitly requires it and will warn on startup if it is not set. For general-purpose servers, mode 0 (heuristic) is safer as it still allows most overcommit while rejecting obviously impossible allocations.
- How do I check which congestion control algorithms are available on my kernel?
- Run 'sysctl net.ipv4.tcp_available_congestion_control'. The output lists all loaded algorithms. If bbr is missing, load the module with 'modprobe tcp_bbr' and check again.
- Can I tune sysctl parameters inside a container or VM?
- Inside unprivileged containers (Docker default, Kubernetes pods) most net.* and vm.* parameters are read-only because they are namespaced to the host kernel. Privileged containers or those with the SYS_ADMIN capability can write some of them. In a full VM you have complete control as if it were bare metal.
Related guides
AI and Artificial-Life Tools on Linux
Set up open-source AI/ML and artificial-life toolkits on Linux: PyTorch, JAX, DEAP, Avida, NetLogo, and RL environments with GPU driver guidance.
Assembly Language on Linux: A Starter Guide
Write x86-64 assembly on Linux from scratch: install NASM and GAS, learn syscalls, assemble and link a working program, then inspect and debug it.
How to Benchmark Disk Performance with fio
Learn to benchmark Linux disk performance with fio: writing job files, testing latency and throughput, and interpreting IOPS and percentile output correctly.
The Linux Boot Process Explained
Trace the full Linux boot sequence from UEFI firmware through GRUB2, the kernel, initramfs, and systemd to your login prompt — with diagnostics at each stage.