sysctl: Tuning Kernel Parameters on Linux

sysctl: Tuning Kernel Parameters on Linux

What You'll Learn

  • How to read and change kernel parameters with sysctl
  • When to use a runtime change (sysctl -w) versus persisting via /etc/sysctl.d
  • How to diagnose why a setting doesn't take effect (precedence, load timing)

Quick Summary

  • Readsysctl <key> (list all with sysctl -a)
  • Runtime changesudo sysctl -w key=value (lost on reboot)
  • Persist → write /etc/sysctl.d/99-custom.conf, then sudo sysctl --system

Assumptions (target environment)

  • systemd-based distros such as Ubuntu 22.04 / 24.04 or RHEL 9
  • Package: sysctl(8) shipped with procps (procps-ng)
  • Changing parameters generally requires root (sudo)

What is sysctl?

Conclusion: sysctl reads and writes the running kernel's tunable parameters through /proc/sys/; key names map directly to that directory tree.

sysctl reads and writes the kernel's tunable parameters. Under the hood, those parameters are files in the virtual filesystem /proc/sys/, and sysctl is a thin wrapper that exposes them in a friendly key = value form.

Dots in a key name map one-to-one to directory separators:

# These refer to the same thing
sysctl net.ipv4.ip_forward
cat /proc/sys/net/ipv4/ip_forward
net.ipv4.ip_forward = 0
0

The main top-level namespaces are:

Prefix Area Typical parameters
net. Networking net.ipv4.ip_forward / net.core.somaxconn
vm. Virtual memory vm.swappiness / vm.overcommit_memory
fs. Filesystem fs.file-max / fs.inotify.max_user_watches
kernel. General kernel kernel.hostname / kernel.pid_max

How do I read the current value?

Conclusion: Use sysctl <key> for one value and sysctl -a for everything; add -n to print the value without the key name.

# A single parameter
sysctl vm.swappiness
vm.swappiness = 60
# All parameters (thousands of lines; combine with grep)
sysctl -a | grep somaxconn
net.core.somaxconn = 4096

To get the value only, use -n (do not print the key name). This is handy in shell scripts that branch on a value.

sysctl -n vm.swappiness
60

Some parameters return "permission denied" for non-root users, so sysctl -a may be incomplete. Run sudo sysctl -a when you need the full list.

How do I change a value temporarily?

Conclusion: sudo sysctl -w key=value applies instantly but is lost on reboot, which makes it ideal for testing and validation.

-w (write) changes the value in the running kernel. It takes effect immediately but reverts on reboot.

# Enable IP forwarding temporarily
sudo sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

Writing directly to /proc/sys/ does the same thing:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

sysctl -w is a temporary change. "I set it but it was gone after reboot" almost always means the value was never persisted. To make it permanent, follow the next section.

How do I make a change permanent?

Conclusion: Put a drop-in file in /etc/sysctl.d/ and apply it with sudo sysctl --system; drop-ins are preferred over editing /etc/sysctl.conf directly.

Persistence means writing key = value lines to a config file. On modern systemd distros, creating a drop-in file under /etc/sysctl.d/ is preferred over editing /etc/sysctl.conf directly, because it is easier to manage and diff.

By convention, name the file NN-name.conf (where NN is a two-digit number). The number controls precedence (see below).

# Example: reduce swapping and enable IP forwarding
sudo tee /etc/sysctl.d/99-custom.conf <<'EOF'
# Custom kernel parameters
vm.swappiness = 10
net.ipv4.ip_forward = 1
EOF

Writing the file alone does not apply it. Load it explicitly:

# Load just this file
sudo sysctl -p /etc/sysctl.d/99-custom.conf

# Or reload every config file from the standard directories
sudo sysctl --system
* Applying /etc/sysctl.d/99-custom.conf ...
vm.swappiness = 10
net.ipv4.ip_forward = 1

Verify the result. After applying, read the value back with sysctl <key> and confirm it matches what you expect.

sysctl vm.swappiness net.ipv4.ip_forward

At boot, systemd-sysctl.service applies these files automatically, so a persisted value survives reboots.

What is the config file precedence?

Conclusion: Files from several directories are merged in lexicographic filename order; for a duplicated key, the lexicographically last filename wins, and /etc/ overrides same-named files elsewhere.

sysctl --system reads *.conf from these directories:

Priority Directory Purpose
High /etc/sysctl.d/ Administrator custom settings
Medium /run/sysctl.d/ Runtime-generated settings
Low /usr/lib/sysctl.d/ Package-shipped defaults

The rules are two-fold:

  1. Files are merged in lexicographic filename order (compared across directories). If the same key appears in multiple files, the one in the file whose name sorts last (largest) wins. That is why a high number like 99-custom.conf makes overriding easy.
  2. If the same filename exists in multiple directories, the one in /etc/ overrides those in /run/ and /usr/lib/. To disable a packaged file, place an empty file of the same name in /etc/sysctl.d/.
# Trace which file sets which key
grep -Rn swappiness /etc/sysctl.conf /etc/sysctl.d/ /usr/lib/sysctl.d/ /run/sysctl.d/ 2>/dev/null

/etc/sysctl.conf is still read, but it is the historical single file. Splitting new settings into drop-ins (/etc/sysctl.d/*.conf) makes it easier to trace where each setting comes from.

Common parameters with examples

Conclusion: Memory, networking, and file-descriptor tunables show up most often in practice; never copy values blindly without understanding them.

Parameter Role Common value
vm.swappiness Swap aggressiveness (0-100, lower favors RAM) 10 on DB servers
vm.overcommit_memory Memory overcommit policy 1 for Redis, etc.
net.ipv4.ip_forward Packet forwarding (required for routers/containers) 1
net.core.somaxconn Max accept-queue length 4096 for busy web servers
fs.file-max System-wide file handle limit Raise for high-connection servers
fs.inotify.max_user_watches inotify watch limit Raise for IDEs/build tools

Why isn't my change taking effect?

Conclusion: Check four things in order: permissions, forgotten reload, an overriding file, and a missing key.

  • Insufficient permission: sysctl -w needs sudo. Operation not permitted means permissions or a container restriction (unprivileged containers block most writes).
  • Forgot to reload: Writing the file is not enough. Confirm you ran sudo sysctl --system (or -p).
  • Overridden by another file: If a value reverts, a lexicographically later file is overriding it. Find the culprit with grep -R <key> /etc/sysctl.d /usr/lib/sysctl.d.
  • Wrong or missing key: sysctl: cannot stat ... means a typo or an unloaded module. Use sysctl -e to ignore unknown-key errors and find the correct name with sysctl -a | grep.
# Check the boot-time apply log (systemd)
journalctl -u systemd-sysctl

Summary and next reads

With sysctl, three patterns cover most real work: read with sysctl <key>, change temporarily with -w, and persist with /etc/sysctl.d/ plus --system. Validate with a runtime change before persisting, and always read the value back afterward, and you will avoid most surprises.