Skip to content

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 -a lists them all.
  • This guide is for parameters under /proc/sys. Kernel command-line parameters (set in the bootloader) and module parameters (set with options in /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

  1. Check the current value of each parameter:

    $ sudo sysctl vm.swappiness net.core.somaxconn
    vm.swappiness = 60
    net.core.somaxconn = 4096
    

    Reading values doesn't need root, but on Debian sysctl is in /usr/sbin, which isn't in an unprivileged user's PATH; sudo finds it everywhere. An error such as sysctl: cannot stat /proc/sys/…: No such file or directory means the name is wrong, or the parameter belongs to a kernel module that isn't loaded.

  2. 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:

    systemd-analyze cat-config sysctl.d
    
    systemd-analyze cat-config sysctl.d
    

    On RHEL, AlmaLinux and Rocky Linux, /etc/sysctl.conf is still read too, through the link /etc/sysctl.d/99-sysctl.conf.

    systemd-analyze cat-config sysctl.d
    

    OpenRC has no equivalent of systemd-analyze; the grep above covers the same directories. sysctl --system, which OpenRC runs at boot, prints the name of each file as it applies it.

  3. 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 = 8192
    

    If something goes wrong, set the old values back the same way, or reboot: nothing has been made permanent yet.

  4. 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 as 90-, 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 = 8192
    

    Use one name = value setting per line. Lines starting with # or ; are comments.

  5. Load the file now, to check it for errors:

    $ sudo sysctl -p /etc/sysctl.d/90-local.conf
    vm.swappiness = 10
    net.core.somaxconn = 8192
    

    sysctl -p prints each setting it applies and an error for any it can't. To apply every configuration file in the order the boot process uses, run sudo sysctl --system instead.

  6. Make sure the boot process applies the files.

    systemd-sysctl.service applies the files early in every boot; it's a static unit and needs no enabling.

    $ systemctl is-active systemd-sysctl.service
    active
    

    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.service applies the files early in every boot; it's a static unit and needs no enabling.

    $ systemctl is-active systemd-sysctl.service
    active
    

    If the tuned service is running (it is on AlmaLinux's cloud image, not on Rocky Linux's), its profile also sets kernel parameters after boot. tuned applies 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 with tuned-adm active.

    systemd-sysctl.service applies the files early in every boot; it's a static unit and needs no enabling.

    $ systemctl is-active systemd-sysctl.service
    active
    

    With OpenRC, the sysctl service runs sysctl --system at boot. Check that it's in the boot runlevel:

    $ rc-update show boot | grep sysctl
                sysctl | boot
    

    If it's missing, add it with sudo rc-update add sysctl boot. With a systemd profile, systemd-sysctl.service applies the files as on the other distributions (systemd profile, not verified).

Verify

Reboot, then check the values:

$ sudo sysctl vm.swappiness net.core.somaxconn
vm.swappiness = 10
net.core.somaxconn = 8192

You can also read the value straight from the kernel's file:

$ cat /proc/sys/vm/swappiness
10

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.