The last post covered sysctl, which you change at runtime. This one is a different animal: boot parameters written into GRUB and handed to the kernel at startup (the kernel command line). They differ from sysctl in one fundamental way — a bad sysctl you can roll back, but a bad boot parameter can leave the machine unable to boot at all, with no error visible over SSH. You’re going to the IPMI/serial console to rescue it.
This string isn’t ours. It’s a “tuned kernel boot line” that circulates online, and people paste the whole thing into GRUB_CMDLINE_LINUX and reboot. We’re keeping it here in full, but let’s be clear: this is not a recommended config, it’s a reference we audited line by line. A fair chunk of it we flatly refuse to enable on production boxes, and we’ll say why below. Reading it grouped by purpose is far more useful than treating it as one long incantation.
An iron rule first: before you touch boot parameters, make sure you have out-of-band management (IPMI/iDRAC/serial) that can reach GRUB. If you don’t have out-of-band and the box is in a remote facility, don’t touch these.
Logging, audit, and boot display
| Parameter | Effect |
|---|---|
loglevel=3 | Kernel console print level set to 3, less console spam. |
rd.udev.log_priority=3 | udev log level in initramfs set to 3. |
rd.systemd.show_status=auto | Show systemd status automatically at boot. |
log_buf_len=2M | Kernel log ring buffer set to 2M, keeps more history for debugging. |
audit=1 | Enable the kernel audit subsystem. |
This group is basically harmless and we keep it. The one caveat: audit=1 has a noticeable cost on boxes with heavy syscall rates, so drop it if you have no compliance requirement.
cgroups and containers
| Parameter | Effect |
|---|---|
systemd.unified_cgroup_hierarchy=false | Disable the cgroup v2 unified hierarchy, fall back to v1. |
systemd.legacy_systemd_cgroup_controller=false | Disable the legacy systemd cgroup controller. |
cgroup_enable=memory | Enable the memory cgroup. |
cgroup_memory=nokmem | Disable kmem accounting (a historical memory-leak workaround). |
swapaccount=1 | Enable swap accounting, needed to limit swap per container. |
These decide which cgroup version the container runtime gets. Be careful forcing a fall back to cgroup v1: modern container runtimes (containerd, recent podman) increasingly default to v2, and falling back to v1 can make newer tooling misbehave. Our rule is to follow the runtime version actually in use rather than reflexively reverting to v1.
Storage and I/O
| Parameter | Effect |
|---|---|
scsi_mod.use_blk_mq=1 | Enable block-layer multi-queue (blk-mq), meaningful for NVMe/multi-queue SSDs. |
On our NVMe/ZFS boxes blk-mq is the default and what we want, so this can stay; on recent kernels it’s effectively the default behavior already.
Memory management and huge pages
| Parameter | Effect and risk |
|---|---|
transparent_hugepage=never | Disable Transparent Huge Pages (THP). On latency-sensitive memory workloads like databases and the ZFS ARC, turning THP off is usually right — it avoids the latency spikes from THP compaction. One of the few we recommend outright. |
cma=128M | Reserve 128M of contiguous memory for CMA. Only specific devices (certain DMA) need it; without that hardware it’s just wasted memory. |
init_on_free=0, init_on_alloc=0 | Disable zeroing memory on alloc/free. Trades a little performance for giving up a layer of info-leak hardening — a direct security-versus-performance tradeoff. |
vsyscall=none | Disable the old vsyscall interface, tightens the attack surface, safe on modern systems. |
Note the source writes domain init_on_free=0, init_on_alloc=0, with a stray domain and a comma. That’s paste noise: the real kernel parameters are just init_on_free=0 and init_on_alloc=0, with no comma between them. Copying it verbatim makes the kernel treat domain as an unrecognized parameter.
CPU power and frequency (chasing low latency)
| Parameter | Effect and risk |
|---|---|
intel_pstate=disable | Disable the intel_pstate scaling driver. |
processor.max_cstate=0 / intel_idle.max_cstate=0 | Forbid the CPU from entering deep C-states. |
idle=halt | Use halt when idle rather than a deeper power-saving state. |
cpufreq.off=1 | Disable frequency scaling. |
pcie_aspm=off | Disable PCIe power saving. |
thermal.off=1 | Disable thermal control. |
This whole group is the classic “trade power for latency”: pin the CPU at high frequency and don’t let it sleep, in exchange for steady low-latency response. It makes sense for real-time forwarding or low-latency trading workloads. The cost is direct: power draw and heat rise sharply, and your power bill and facility cooling have to keep up. And thermal.off=1 deserves special caution — turning off thermal control means the kernel no longer throttles to protect against overheating, so a genuine cooling problem can cook the hardware. We don’t enable that one on production boxes. An ordinary application box has no need for this group at all.
Interrupts, locking, and RCU
| Parameter | Effect and risk |
|---|---|
threadirqs | Move hard-IRQ handling into kernel threads, easier to schedule and isolate. |
nosoftlockup | Disable soft-lockup detection. |
nmi_watchdog=0 | Disable the NMI watchdog, saves a little per-core overhead. |
rcu_nocbs=0-64 | Offload RCU callbacks for CPUs 0–64 elsewhere, used with CPU isolation for low latency. |
rcupdate.rcu_expedited=1 | Expedite RCU grace periods, lowers latency at a slight CPU cost. |
rcutree.kthread_prio=2 | Raise the priority of the RCU kernel threads. |
skew_tick=1 | Stagger per-core timer interrupts to reduce jitter from simultaneous wakeups. |
no_timer_check | Skip the timer IRQ routing check, saves a little boot time. |
noreplace-smp | Disable SMP-related code replacement optimization. |
This group is for a low-latency box you’ve specifically tuned for CPU isolation. In particular, rcu_nocbs=0-64 only matters when you’ve actually used isolcpus/nohz_full to isolate those cores; otherwise it does nothing. nosoftlockup + nmi_watchdog=0 again turns off the detection we treated as a safety net in the last post — you save the overhead and lose the means to notice a hang. Be clear about that tradeoff.
Virtualization and IOMMU
| Parameter | Effect |
|---|---|
intel_iommu=on / amd_iommu=on | Enable the IOMMU, a prerequisite for PCI passthrough. |
iommu.strict=0 | Non-strict mode, defers TLB flushes for performance at the cost of slightly weaker isolation for passthrough devices. |
kvm-intel.nested=1 | Enable nested virtualization. |
kvm-intel.vmentry_l1d_flush=never | Disable the L1D flush on VM entry — one of the L1TF mitigations, see the security section below. |
pci=realloc | Allow reallocating PCI resources, fixes insufficient BAR space on some devices. |
For GPU/NIC passthrough intel_iommu=on is mandatory. iommu.strict=0 and the various flush=never flags all trade isolation for performance — think hard in a multi-tenant environment.
NIC naming
| Parameter | Effect |
|---|---|
net.ifnames=0 | Disable systemd’s predictable NIC naming, back to traditional names like eth0. |
biosdevname=0 | Likewise disable BIOS-style naming. |
These two are purely an ops-style choice. The upside is short names that are easy to script; the downside is that on multi-NIC boxes traditional naming order isn’t stable, so names can swap after you reseat a card, which makes automation easier to trip over. We only use this on boxes where the NICs are fixed and bound by MAC.
Graphics
| Parameter | Effect and risk |
|---|---|
nomodeset | Disable Kernel Mode Setting (KMS). |
vt.cur_default=50 | Set the virtual-terminal cursor. |
nomodeset deserves to be called out: it disables mode setting in the kernel graphics driver. It may not matter for a pure server, but on a machine that needs the graphics driver to work (the GPU node in the previous post, for instance), nomodeset will keep the driver from coming up. Whether a parameter like this is “good” depends entirely on the machine’s role; you can’t copy it blindly.
Security mitigations — the highest-risk group
mitigations=off noibrs nopti l1tf=off nospec_store_bypass_disable noibpb spectre_v2_user=off spectre_v2=off
| Parameter | Effect |
|---|---|
mitigations=off | Turn off all CPU vulnerability mitigations at once (this one line equals everything below). |
nopti | Disable KPTI (the Meltdown mitigation). |
noibrs / noibpb / spectre_v2=off / spectre_v2_user=off | Disable the Spectre v2 mitigations. |
l1tf=off | Disable the L1TF (L1 Terminal Fault) mitigation. |
nospec_store_bypass_disable | Disable the SSB mitigation. |
This is the part of the whole string we most need to warn about. Turning these mitigations off does win back the performance the Meltdown/Spectre patches cost, and on some compute-heavy workloads the gain is real. But the price is exposing the machine to known side-channel vulnerabilities. On a multi-tenant box, one running other people’s code, or any machine with not-fully-trusted workloads, never enable it — it’s tearing down the CPU’s security isolation on purpose. Only consider it on a physically isolated, single-tenant box where you’ve confirmed the workload is fully trusted and you’ve actually measured the bottleneck here, and record it as an explicit risk decision rather than pasting it into GRUB offhand.
Everything else
| Parameter | Effect and risk |
|---|---|
selinux=0 | Disable SELinux. Less hassle, but also removes a layer of mandatory access control. |
mce=off | Disable Machine Check Exceptions. Dangerous: MCE is how the hardware reports memory/CPU errors, so disabling it means going blind to hardware faults in progress. We don’t enable it. |
noresume | Disable resume from hibernation; servers don’t hibernate anyway, so harmless. |
workqueue.power_efficient=0 | Disable power-efficient workqueues, favors performance. |
cryptomgr.notests | Skip the crypto self-tests at boot, saves a little boot time. |
nosync | Disable related busy-wait behavior. |
nf_conntrack.acct=0 | Disable conntrack flow accounting, saves a little per-connection overhead — somewhat meaningful on the hundreds-of-thousands-of-connections box from the last post. |
crashkernel=384M-2G:64M,2G-:128M | Reserve crash-kernel memory for kdump, scaled by physical RAM. Keep it if you want crash dumps. |
Full reference (kept verbatim)
Below is the complete single line from the source. Once more: this is not a config to copy. It’s a thing to evaluate. Decide the mitigations=off group, mce=off, thermal.off=1, and nomodeset explicitly based on the machine’s role, and clean up the domain ... , paste noise.
loglevel=3 selinux=0 audit=1 rd.systemd.show_status=auto rd.udev.log_priority=3 systemd.unified_cgroup_hierarchy=false systemd.legacy_systemd_cgroup_controller=false scsi_mod.use_blk_mq=1 crashkernel=384M-2G:64M,2G-:128M workqueue.power_efficient=0 domain init_on_free=0, init_on_alloc=0 cma=128M vsyscall=none nosoftlockup mce=off threadirqs noresume nmi_watchdog=0 vt.cur_default=50 transparent_hugepage=never cgroup_enable=memory cgroup_memory=nokmem swapaccount=1 nf_conntrack.acct=0 log_buf_len=2M intel_pstate=disable processor.max_cstate=0 intel_idle.max_cstate=0 thermal.off=1 pci=realloc pcie_aspm=off cpufreq.off=1 idle=halt net.ifnames=0 biosdevname=0 mitigations=off noibrs nopti l1tf=off nomodeset nospec_store_bypass_disable noibpb spectre_v2_user=off spectre_v2=off kvm-intel.vmentry_l1d_flush=never no_timer_check noreplace-smp kvm-intel.nested=1 nosync iommu.strict=0 intel_iommu=on amd_iommu=on cryptomgr.notests rcu_nocbs=0-64 rcupdate.rcu_expedited=1 rcutree.kthread_prio=2 skew_tick=1
The right way to do this: pick the handful of flags that match your machine’s role, add one group at a time, run grub2-mkconfig, reboot, confirm from the out-of-band console that it comes up, then verify that what you turned off didn’t break anything. There is no “one universal boot line” to copy — every machine’s role is different, and so is which flag helps and which one kills it.
