| Tested on | Red Hat Enterprise Linux 10.2 (kernel 6.12) |
|---|---|
| Package | procps-ng 4.0.4 (sysctl) |
| Applies to | RHEL, Rocky Linux, AlmaLinux, Fedora, Debian, Ubuntu, and other GNU/Linux systems with procps sysctl |
| Privilege | root or sudo to change kernel tunables and write files under /etc/sysctl.d/ |
| Scope | Annotated list of performance-related sysctl parameters — what each controls, what to check, and typical impact — plus persisting changes and TuneD. Not a paste-and-go sysctl.conf dump. |
| Related guides | Transparent Huge Pages iostat command Linux commands cheat sheet sysctl command Linux swap and swappiness |
Copy-paste sysctl.conf lists rank because they answer one question fast: which parameters should I look at? Large GitHub gists and old blog templates rarely explain what each line does on your server, what counter proves the knob is the bottleneck, or what goes wrong when you paste the whole file onto the wrong workload.
The sections below walk parameter by parameter. Each entry uses bullets for what the setting controls, what to observe on your host, and what changes when you raise or lower the value. Read your defaults first, change one value with sysctl -w, re-check on your real workload, then persist in /etc/sysctl.d/ only when the signal improved.
net.ipv4.ip_forward, martian logging, and similar) are policy settings. They do not make a server faster, so they are omitted here.
Memory, swap, and when data is flushed to disk
These knobs control how the kernel uses RAM for the page cache, swap, and buffered writes. They do not make a slow disk faster; they change when data sits in RAM and when flush work hits the disk.
vm.swappiness
- Controls the kernel's preference between reclaiming file-backed cache and swapping anonymous memory when it needs to reclaim RAM.
- Think of it as a relative cost setting on a scale of 0–200, not a "start swapping at X% RAM" knob. The default is commonly
60; at that value the kernel treats swap I/O and filesystem paging costs as roughly equal. - Lower values tell the kernel that swap I/O is relatively expensive, so it prefers reclaiming file cache first. Higher values make swapping anonymous pages more acceptable, including above
100when swap is fast (zram, zswap, or unusually fast swap devices). - Check
vmstat 1,sar -W, and your application's latency while the host is under memory pressure. A machine merely showing some swap usage is not enough reason to change it. - At
0, swap is not disabled; the kernel delays initiating swap until free and file-backed pages fall below a zone watermark. - Lowering the value can help when swapped application pages cause noticeable latency and enough file cache can safely be reclaimed. Raising it can make sense when swap is fast.
- Avoid universal recommendations such as
vm.swappiness=10; the useful value depends on the relative cost of swap I/O and filesystem paging on that host. See Linux swap and swappiness for a deeper pass on swap behaviour.
vm.dirty_ratio
- Sets the dirty-memory threshold at which a process generating writes begins writeback itself.
- The percentage is calculated from memory the kernel considers available for dirty pages, including free and reclaimable pages; it is not simply a percentage of total installed RAM.
- File writes are normally buffered in memory first. As dirty pages accumulate, reaching this threshold causes writers to participate in writeback instead of continuing to dirty memory without restraint.
- Watch
Dirty:in/proc/meminfo, disk latency withiostat, and application flush or checkpoint latency during sustained writes. - Raising the value permits a larger dirty-memory burst before writers are affected. That can make buffered writes appear faster temporarily, but it leaves more work for later writeback and can produce larger latency spikes.
- Lowering it makes writeback pressure reach writers sooner, reducing outstanding dirty data but potentially reducing burst-write throughput.
- This changes when write I/O is performed; it does not increase the physical throughput of the storage device.
vm.dirty_background_ratio
- Sets the dirty-memory level at which background kernel flusher threads begin writeback.
- Like
dirty_ratio, the percentage is calculated from available free and reclaimable memory rather than total RAM. - This threshold normally acts before
dirty_ratio: background writeback can begin while applications continue writing normally, whereas the higher dirty threshold eventually causes writers themselves to participate in writeback. - Lowering it starts background flushing earlier and can keep the dirty-data pool smaller. Raising it allows more dirty data to accumulate before background writeback starts.
- Look at dirty-memory growth and storage latency during write bursts. If the disk is already saturated continuously, changing this value mostly changes where the waiting occurs rather than fixing the storage bottleneck.
vm.dirty_expire_centisecs
- Controls how old dirty data must become before kernel flusher threads consider it eligible for writeback.
- The value is measured in hundredths of a second; for example,
3000means 30 seconds. - Reaching this age does not mean the page is flushed at that exact instant. It becomes eligible and is written when a flusher thread next runs.
- Lower values make older dirty data eligible sooner, which can reduce long-lived dirty-data buildup but cause more frequent writeback activity.
- Higher values allow dirty data to remain eligible later, which may suit short bursts but can leave a larger amount of old dirty data outstanding.
- Diagnose this together with
dirty_writeback_centisecs,dirty_background_ratio, and actual dirty-memory behaviour rather than tuning it in isolation.
vm.vfs_cache_pressure
- Controls how aggressively the kernel reclaims cached filesystem metadata, primarily dentries and inodes, relative to other reclaimable caches.
- Dentries help the kernel resolve path names, while inode cache entries hold filesystem object metadata. Keeping them cached can make repeated directory traversals and metadata-heavy workloads cheaper.
- Current kernel documentation also notes it should be considered together with
vfs_cache_pressure_denomwhere present. - Lowering the value tells the kernel to retain dentry and inode caches more strongly. Raising it makes those objects stronger reclaim candidates when memory is needed elsewhere.
- Most relevant to workloads that repeatedly traverse very large directory trees, metadata-heavy file servers, backup scanners, and similar jobs.
- Do not set it to
0casually: kernel documentation warns that preventing dentry and inode reclaim under memory pressure can lead to out-of-memory conditions. - Very high values can also hurt performance because reclaim itself requires CPU work and locking.
Open files and per-process memory limits
These limits appear in almost every sysctl template. On modern servers they are often already high enough; the error you see may come from a different layer.
fs.file-max
- System-wide ceiling on open file structures. Every open file, socket, pipe, and similar object on the host counts toward this limit.
- It is not the per-process limit from
ulimit -n. When you seetoo many open files, checkulimit -nand systemdLimitNOFILEbefore assuming this sysctl is the cap. - Raising it only matters when kernel accounting shows the global count approaching the limit during legitimate high-connection workloads.
- On many 64-bit hosts the value is already enormous. See ulimit in Linux when the failure names a process limit.
vm.max_map_count
- Caps how many memory mapped regions one process may create (
mmap, shared libraries, thread stacks). - Search engines, large Java heaps, and similar apps that map many small regions can hit vendor-documented minimums on older images.
- Check application documentation and compare
sysctl vm.max_map_countto the required minimum. - Current distributions often ship
1048576, which already matches current Elasticsearch guidance. Raising without a documented requirement adds nothing.
kernel.pid_max
- Highest process ID number the kernel will assign before IDs wrap and reuse.
- It does not cap how many processes you may run;
ulimit -uand cgroup limits do that. - Tune only when documentation or an extreme fork rate scenario references PID exhaustion, which is rare on current distributions.
Network buffers and connection queues
These settings shape socket memory and kernel queues before traffic reaches your application.
net.core.rmem_default and net.core.wmem_default
- Set the default receive and send socket buffer sizes for sockets that use the generic networking defaults.
- Do not confuse them with TCP's
tcp_rmemandtcp_wmem. TCP has its own default buffer values, which override the generic core defaults for normal TCP sockets. - These core defaults matter when an application or protocol relies on the generic socket-buffer defaults instead of choosing its own size.
- Raising them increases the initial memory allowance for every affected socket, so changing them globally can multiply memory use across thousands of sockets.
- For TCP throughput problems, investigate
tcp_rmem,tcp_wmem, RTT, congestion, and the application's socket settings before changing these generic defaults.
net.core.rmem_max and net.core.wmem_max
- Set the maximum receive and send socket-buffer sizes available through the generic socket-buffer interface, including applications that request a size with
SO_RCVBUForSO_SNDBUF. - They are not simply the TCP autotuning maximums. TCP has separate
tcp_rmemandtcp_wmemranges for automatically selected buffers. - Check whether the application explicitly sets its socket buffers before changing these values. If it never requests larger buffers, increasing the core maximum may have no effect.
- Raise them when an application needs to request larger socket buffers and the existing core ceiling rejects or clips that request.
- Higher limits permit larger per-socket allocations, so the memory cost becomes significant when many sockets use those larger buffers simultaneously.
- Do not automatically mirror
tcp_rmem[2]andtcp_wmem[2]into these settings; tune according to how the application actually configures its sockets.
net.core.somaxconn
- Sets the kernel-wide upper limit for the backlog value an application can request with
listen(). - When a client connects, the TCP handshake finishes first. The connection then waits in kernel memory until your program calls
accept()to hand it to a worker. - Your app also passes a queue size in
listen(), but the kernel never allows more thansomaxconn, and the application's own backlog request also matters. - If many clients connect at once and your app is slow to
accept(), the waiting line can fill. Extra connections then wait or fail. With the defaulttcp_abort_on_overflow=0, clients usually wait rather than get an error right away. - Run
ss -lntunder load: Recv-Q counts connections waiting now; Send-Q shows the configured backlog limit. If Recv-Q nears Send-Q and ListenOverflows or ListenDrops rise innstat, this limit is involved. See the ss command. - Raising the value helps only when workers are briefly busy but still accept quickly most of the time; a longer queue does not fix an app that never calls
accept()promptly.
net.core.netdev_max_backlog
- Sets the maximum number of incoming packets that may wait in the kernel's input backlog when packets arrive faster than the networking stack can process them.
- This is not the NIC hardware ring itself; it is a software-side backlog in the receive processing path.
- Inspect
/proc/net/softnet_statcolumn 2 (hexadecimal drop count per CPU):
awk '{print NR-1, $2}' /proc/net/softnet_stat- Record the second column, reproduce the workload, and check whether the counter increases. Those values are cumulative since boot; an old non-zero value by itself does not prove the queue is currently overflowing.
- If the counter climbs during your workload, raising this value may help short ingress bursts; if column 2 stays flat under load, the bottleneck is elsewhere.
net.core.optmem_max
- Limits ancillary and options memory associated with an individual socket, separate from the normal send and receive data buffers.
- Ancillary data includes control messages passed with interfaces such as
sendmsg()andrecvmsg(); TCP transmit zero-copy also uses this limit for internal structures. - This is not a general TCP throughput buffer. Change it only when an application documents a requirement or fails while allocating ancillary socket data.
TCP buffer sizes for throughput
TCP buffer autotuning and global TCP memory limits interact with the net.core.* ceilings above.
net.ipv4.tcp_rmem
- Defines three receive-memory values for TCP sockets: minimum, initial/default, and maximum automatically selected receive-buffer size.
- The first value is memory TCP guarantees to a socket even under moderate memory pressure. The second is the initial receive-buffer size. The third is the largest receive buffer TCP autotuning may select.
- TCP uses these values dynamically as conditions change. If an application explicitly sets
SO_RCVBUF, automatic receive-buffer tuning is disabled for that socket, so blindly increasingtcp_rmemmay not affect that application. - Check WAN or cross-region RTT, throughput versus link capacity, and TCP retransmits. Low retransmits with throughput stuck below what the link should carry may point to buffer limits. High retransmits after you raise buffers often means congestion on the path.
- On long, fast links, autotuning may need a larger max so more data can stay in flight:
buffer (bytes) ≈ (bandwidth bits/sec × RTT sec) ÷ 8- Example: 1 Gbit/s with 100 ms RTT needs about 12.5 MB in flight per flow. Large buffers on paths with small queues can add delay and retransmits.
net.ipv4.tcp_wmem
- Defines the minimum, initial/default, and maximum memory available for automatically tuned TCP send buffers.
- The third value limits automatic send-buffer growth; applications that explicitly set
SO_SNDBUFfollow the explicit socket-buffer path instead. - TCP's default send value overrides
net.core.wmem_default, andtcp_wmemmax does not overridenet.core.wmem_max. - Tune together with receiver
tcp_rmemon WAN paths. The receiver advertises how much data it can accept; an undersized far end caps the flow even when the sender is generous.
net.ipv4.tcp_mem
- Controls system-wide TCP memory pressure using three thresholds:
min,pressure, andmax. - Unlike
tcp_rmemandtcp_wmem, these values are expressed in memory pages and apply to TCP memory use across the networking namespace rather than to one connection. - Below
min, TCP does not consider memory usage problematic. As usage reaches pressure and high levels, the stack becomes increasingly conservative with memory allocation. - This is a host-wide pressure safeguard, not the normal first knob for improving one TCP flow.
- Investigate it only when large numbers of concurrent TCP sockets create genuine socket-memory pressure; inspect
/proc/net/sockstatrather than changing it because a single WAN flow is slow. - Do not manually raise this for ordinary throughput tuning.
net.ipv4.udp_mem
- Sets system-wide UDP memory accounting thresholds, expressed in memory pages, for data queued by UDP sockets.
- It is not a per-socket receive-buffer size; per-socket receive behaviour is controlled separately by settings such as
rmem_maxandudp_rmem_min. - The second and third fields exist largely to mirror the
tcp_memformat. - Check UDP socket-memory use in
/proc/net/sockstatand packet-drop counters before considering this parameter. - Do not copy
tcp_memvalues intoudp_mem; they are separate protocol memory pools and the kernel calculates their defaults from available memory.
New connections, idle links, and closed sockets
These parameters affect connection setup, idle detection, and socket table churn. They do not raise raw throughput on an established bulk flow.
net.ipv4.tcp_max_syn_backlog
- Limits the number of remembered incoming TCP connection requests in
SYN_RECVthat have not yet received the client's final ACK. - This is a per-listener limit and is separate from
somaxconn, which caps the completed-connection accept backlog. - Use when connect bursts overwhelm the handshake stage. Do not use
softnet_statcolumn 2 as the signal; that column is for kernel input backlog drops. - Check
TcpExtSyncookiesSent,TcpExtListenQueueOverflows, or rising SYN-RECV counts under connect bursts. - Wrong fix for accept-queue overflow (
somaxconn/ Recv-Q) or for kernel input backlog drops.
net.ipv4.tcp_fin_timeout
- Controls how long an orphaned TCP connection can remain in
FIN_WAIT_2before the kernel aborts it. FIN_WAIT_2means the local side has closed its sending direction and received acknowledgment of its FIN, but the remote peer has not yet closed its side.- For a connection still owned by an application, remaining in this state can be legitimate; this sysctl applies to orphaned connections that no application references anymore.
- Do not confuse this with TIME-WAIT. Changing
tcp_fin_timeoutis not a general way to reduce TIME-WAIT sockets. - Investigate it only when orphaned
FIN_WAIT_2sockets accumulate abnormally because peers fail to finish closing connections. - Lowering it removes orphaned
FIN_WAIT_2sockets sooner, but an aggressive value can terminate connections whose remote side is legitimately slow to close. - Leave the default unless you have measured a specific
FIN_WAIT_2accumulation problem.
net.ipv4.tcp_keepalive_time, tcp_keepalive_probes, tcp_keepalive_intvl
- Set kernel defaults for TCP keepalive on sockets where the application enabled
SO_KEEPALIVE: idle time before the first probe, probe count before declaring the peer dead, and interval between probes. - Relevant for long-lived connections through stateful firewalls or when peers disappear without closing cleanly.
- Application-level keepalive may already exist; check before duplicating.
- Lowering the time or interval detects dead peers faster on idle links. Raising them reduces probe traffic and keeps quiet connections up longer.
- Firewalls with short idle timeouts may still drop the flow unless the app sends its own keepalive.
- For SSH idle drops, client
ServerAliveIntervalis often the clearer fix. See keep alive SSH sessions.
net.ipv4.tcp_max_tw_buckets
- Sets the maximum number of TIME-WAIT sockets the kernel will retain simultaneously.
- Primarily a protection against excessive kernel memory consumption, not a routine performance knob.
- If the limit is exceeded, excess TIME-WAIT sockets are destroyed immediately and the kernel logs a warning.
- Do not lower it merely to make
ssshow fewer TIME-WAIT sockets. If a legitimate workload needs more entries, investigate connection churn and available memory first.
net.ipv4.tcp_tw_reuse
- Controls whether the kernel may reuse suitable TIME-WAIT sockets for new connections when protocol-safety checks allow it.
- Current kernels support
0(off),1(global reuse), and2(loopback-only reuse); upstream documentation lists2as the default. - Not a generic fix for large TIME-WAIT counts. Port exhaustion is better diagnosed from the actual connection pattern,
ip_local_port_range, application connection reuse, and client behaviour. - Kernel documentation advises against changing this setting without expert guidance because safe reuse depends on TCP timestamp assumptions.
net.ipv4.tcp_tw_recycle
- Removed in Linux 4.12. It caused serious breakage behind NAT and load balancers because of timestamp handling.
- If a template still sets
tcp_tw_recycle=1, the file is outdated.
net.ipv4.tcp_syncookies
- Enables SYN cookies as a fallback when a listener's SYN backlog overflows.
- Primary purpose is resilience against SYN-flood pressure, not increasing normal server throughput.
- If SYN cookies are being generated during legitimate traffic, investigate the connection rate,
tcp_max_syn_backlog, application behaviour, and other queue limits rather than relying on cookies as normal capacity. - Leave the distribution default unless you have a specific reason to change it.
net.ipv4.ip_local_port_range
- Defines the range from which the kernel automatically chooses local TCP and UDP ports for outbound connections and sockets bound with an automatically selected port.
- Relevant on clients, proxies, NAT gateways, or other hosts creating very large numbers of concurrent outbound connections from the same address.
- Port exhaustion can surface as connection failures such as
EADDRNOTAVAIL, but expanding the range is only one part of the diagnosis. - TIME-WAIT duration, connection reuse, destination tuples, and reserved local ports also matter.
- A wider range gives the kernel more candidate ephemeral ports; a narrower range reduces them.
- Check
ip_local_reserved_portsbefore changing the range so automatically allocated ports do not collide with ports reserved for local services. - Current kernel defaults are often
32768 60999, and the lower bound must also respectip_unprivileged_port_start.
CPU scheduler settings on modern kernels
Fair-scheduler sysctl names from older tuning guides largely disappeared as the kernel moved from classic CFS toward EEVDF.
- The common scheduler values from old
sysctl.confperformance templates are not current general-purpose tuning interfaces on RHEL 10.2 and similar kernels. - Check what your kernel actually exposes instead of carrying old names forward.
sysctl kernel.sched_min_granularity_ns kernel.sched_latency_ns kernel.sched_wakeup_granularity_nssysctl: cannot stat /proc/sys/kernel/sched_min_granularity_ns: No such file or directory
sysctl: cannot stat /proc/sys/kernel/sched_latency_ns: No such file or directory
sysctl: cannot stat /proc/sys/kernel/sched_wakeup_granularity_ns: No such file or directory- CPU throughput and latency today are shaped by frequency governors, IRQ and RPS affinity, cgroup CPU limits, and TuneD profiles.
- Pasting legacy
sched_*names intosysctl.don a modern host produces errors or silent no-ops. - On this lab host, scheduler migration hints appear under debugfs (
/sys/kernel/debug/sched/migration_cost_ns), not as a writablekernel.sched_migration_cost_nssysctl.
Check what your system uses today
Snapshot defaults before editing any template. Network buffers commonly copied from gists:
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem net.core.rmem_max net.core.wmem_max net.core.somaxconnnet.ipv4.tcp_rmem = 4096 131072 6291456
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.rmem_max = 212992
net.core.wmem_max = 212992
net.core.somaxconn = 4096On this host TCP autotuning may reach about 6 MB receive while setsockopt requests cap at 212992 bytes.
Writeback and common limits:
sysctl vm.dirty_ratio vm.dirty_background_ratio vm.swappiness fs.file-max vm.max_map_countvm.dirty_ratio = 20
vm.dirty_background_ratio = 10
vm.swappiness = 60
fs.file-max = 9223372036854775807
vm.max_map_count = 1048576Listen-queue counters under load:
nstat -az | grep -E 'ListenOverflows|ListenDrops'TcpExtListenOverflows 0 0.0
TcpExtListenDrops 0 0.0Save sysctl changes after you verify them
After one parameter helps on your workload, persist it in a drop-in:
/etc/sysctl.d/90-app-network.conf
# 2026-08-15 — WAN replication; raised tcp autotuning max after low-retransmit plateau.
net.ipv4.tcp_rmem = 4096 131072 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864Load without rebooting:
sysctl --system* Applying /usr/lib/sysctl.d/50-redhat.conf ...
* Applying /etc/sysctl.d/90-app-network.conf ...
net.ipv4.tcp_rmem = 4096 131072 67108864Confirm the running value:
sysctl -n net.ipv4.tcp_rmem4096 131072 67108864Reload rules and override order: sysctl reload without reboot.
TuneD profiles or your own sysctl file
- TuneD profile — broad throughput or latency goals when you want one maintained, reversible bundle instead of dozens of hand-picked lines.
- Hand
sysctl.d— one or two parameters you verified from the list above. - Defaults — when checks show no bottleneck; distribution values are already reasonable for most hosts.
tuned-adm list- balanced - General non-specialized tuned profile
- latency-performance - Optimize for deterministic performance at the cost of increased power consumption
- network-throughput - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
- throughput-performance - Broadly applicable tuning that provides excellent performance across a variety of common server workloads
Current active profile: balancedDetails in TuneD profiles.
Summary
Readers search for sysctl lists because they need a map of important parameters. What copy-paste files omit is plain explanation: what each knob does, what to check on your host, what usually improves when you tune it, and what commonly breaks.
Work one parameter at a time. Read with sysctl, match a metric the knob controls (Recv-Q versus Send-Q, rising softnet_stat drop counters under load, dirty memory, swap-in under pressure), change a single value, and persist only when the metric improves. Your RTT, disk type, and flush behaviour will not match a lab VM or a ten-year-old gist. Treat examples as illustrations of trade-offs, not targets to paste. For broad goals, TuneD beats maintaining a forty-line file; for one proven bottleneck, a commented drop-in under sysctl.d is enough.
References
- sysctl.d(5) — freedesktop.org
- Red Hat — Network troubleshooting and performance tuning (RHEL 10)
- Linux kernel — IP sysctl documentation
- Linux kernel — Documentation for /proc/sys/vm
- Linux kernel — Documentation for /proc/sys/kernel
- EEVDF scheduler — kernel scheduler documentation

