How to change kernel parameters persistently¶
You need to change a kernel parameter, such as vm.swappiness or net.core.somaxconn, and keep the new value after a reboot.
sysctl -w changes a value only until the next boot.
This guide puts the setting in a file in /etc/sysctl.d/, which every distribution covered here reads at boot, applies it immediately, and checks after a reboot that it stuck.
The example lowers vm.swappiness to 10 and raises net.core.somaxconn (the maximum queue of pending connections on a listening socket) to 8192.
Replace them with the parameters you need; the defaults on each distribution are listed in Common sysctl parameters.
Before you begin¶
- You need root access through
sudo. - Know the exact name of the parameter. Names use dots (
vm.swappiness) and correspond to files below/proc/sys/(/proc/sys/vm/swappiness);sysctl -alists them all. - This guide is for parameters under
/proc/sys. Kernel command-line parameters (set in the bootloader) and module parameters (set withoptionsin/etc/modprobe.d/) are configured differently.
Warning
Some parameters can make a machine unreachable or unstable: network parameters such as net.ipv4.conf.*.rp_filter or net.ipv4.ip_forward change how packets are routed and filtered, and memory parameters such as vm.overcommit_memory = 2 can make programs fail to start.
Change a remote server's network or memory parameters with console access available, try each value with sysctl -w first, and keep a second SSH session open until you've checked the result.
Steps¶
-
Check the current value of each parameter:
Reading values doesn't need root, but on Debian
sysctlis in/usr/sbin, which isn't in an unprivileged user'sPATH;sudofinds it everywhere. An error such assysctl: cannot stat /proc/sys/…: No such file or directorymeans the name is wrong, or the parameter belongs to a kernel module that isn't loaded. -
Find out whether any configuration file already sets them, so you know what your file has to override:
grep -rs -e swappiness -e somaxconn /etc/sysctl.conf /etc/sysctl.d/ /run/sysctl.d/ /usr/local/lib/sysctl.d/ /usr/lib/sysctl.d/ || echo "not set in any sysctl file"Files are read from those directories together, in the order of their file names; for a parameter set in several files, the file whose name sorts last wins. A file in
/etc/sysctl.d/replaces a file with the same name in/usr/lib/sysctl.d/or/run/sysctl.d/. Packages install their files in/usr/lib/sysctl.d/; never edit those, because an update overwrites them.On the systemd distributions you can also display the effective configuration, file by file:
On RHEL, AlmaLinux and Rocky Linux,
/etc/sysctl.confis still read too, through the link/etc/sysctl.d/99-sysctl.conf.OpenRC has no equivalent of
systemd-analyze; thegrepabove covers the same directories.sysctl --system, which OpenRC runs at boot, prints the name of each file as it applies it. -
Try the new values at run time first, and check that the system behaves as expected:
$ sudo sysctl -w vm.swappiness=10 net.core.somaxconn=8192 vm.swappiness = 10 net.core.somaxconn = 8192If something goes wrong, set the old values back the same way, or reboot: nothing has been made permanent yet.
-
Create a file in
/etc/sysctl.d/with the settings. The name must end in.conf; start it with a number that sorts after the distribution's own files, such as90-, so that your values win:# /etc/sysctl.d/90-local.conf: local kernel parameter settings. # Prefer RAM for process memory over page cache. vm.swappiness = 10 # Allow longer queues of pending connections for busy servers. net.core.somaxconn = 8192Use one
name = valuesetting per line. Lines starting with#or;are comments. -
Load the file now, to check it for errors:
sysctl -pprints each setting it applies and an error for any it can't. To apply every configuration file in the order the boot process uses, runsudo sysctl --systeminstead. -
Make sure the boot process applies the files.
systemd-sysctl.serviceapplies the files early in every boot; it's a static unit and needs no enabling.On Debian 13 and Ubuntu 26.04 there is no
/etc/sysctl.conf, and the boot process doesn't read one if you create it: use/etc/sysctl.d/.systemd-sysctl.serviceapplies the files early in every boot; it's a static unit and needs no enabling.If the
tunedservice is running (it is on AlmaLinux's cloud image, not on Rocky Linux's), its profile also sets kernel parameters after boot.tunedapplies its profile and then reapplies the settings from the sysctl configuration files, so values in/etc/sysctl.d/still win; check which profile is active withtuned-adm active.systemd-sysctl.serviceapplies the files early in every boot; it's a static unit and needs no enabling.With OpenRC, the
sysctlservice runssysctl --systemat boot. Check that it's in thebootrunlevel:If it's missing, add it with
sudo rc-update add sysctl boot. With a systemd profile,systemd-sysctl.serviceapplies the files as on the other distributions (systemd profile, not verified).
Verify¶
Reboot, then check the values:
You can also read the value straight from the kernel's file:
Troubleshooting¶
The value is right after sysctl -p but wrong after a reboot.
Something applied later overrides it.
Look for another file that sets the same parameter and sorts after yours (step 2), and rename yours, for example to 99-local.conf.
Other services can also change parameters after boot: tuned on the RHEL family, container engines (which turn on net.ipv4.ip_forward), and network managers for per-interface settings.
Search their configuration for the parameter's name.
sysctl: cannot stat /proc/sys/…: No such file or directory at boot.
The parameter belongs to a kernel module that wasn't loaded when the sysctl files were applied, for example net.netfilter.nf_conntrack_max before nf_conntrack is loaded.
Load the module at boot (a file in /etc/modules-load.d/, which systemd and OpenRC's modules service both read; on Gentoo the modules setting in /etc/conf.d/modules also works), or set it as a module option instead, if the module offers one.
A per-interface setting such as net.ipv4.conf.eth1.rp_filter doesn't apply.
The interface didn't exist yet when the files were applied.
On systemd systems, systemd-sysctl is run again for each network interface as it appears, so a setting for a specific interface name applies when that interface is created.
Otherwise, set net.ipv4.conf.default.*, which is copied to interfaces created afterwards.
sysctl: permission denied on key ….
You ran it without sudo, or the parameter is read-only, or (inside a container) the kernel doesn't let the container change it.
Related¶
- Reference: Common sysctl parameters
- Explanation: Load average and memory
- Explanation: Control groups
- How-to: How to find what is using CPU and memory
- How-to: How to limit a service's resources