Bali, Indonesia
Insights

Why Load Average Is High While Your Linux CPU Sits Mostly Idle

October 21, 2026
0:00
You open top because a monitoring alert says load average is 30 on a 4-core server. You expect a wall of busy processes. Instead, the CPU line says the machine is mostly idle, and nothing in the process list is using much CPU at all. So is the server overloaded or not, and should you be buying more cores? Usually not. On Linux, a high load with idle CPU almost always means processes are waiting on something, most often a disk or a network filesystem, and adding CPU will not change that. The useful question is which of three things is going on: slow local storage, a stuck network mount, or a CPU shortage that only looks idle at the moment you checked. This guide walks through how to tell them apart and what each answer means for the fix.
Load average is the three numbers you see in uptime or the top line of top. They are smoothed averages over roughly 1, 5, and 15 minutes of how many tasks were in one of two states. The first state is runnable (R): the task is running on a CPU or waiting in line for one. That is the part everyone expects. The second state is uninterruptible sleep, shown as D in ps and top. A task enters D when it is waiting inside the kernel for something it cannot safely abandon halfway, typically a disk read or write, or a reply from an NFS server. It is not using CPU while it waits. It is just stuck in line for I/O. Linux counts both states in load average. Many other Unix-like systems only count runnable tasks, which is why the "load should stay below the core count" rule of thumb comes from CPU thinking and does not translate cleanly to Linux. Twenty processes waiting on a dead disk will push load to 20 while the CPUs sit at nearly 100% idle. This is also why customers and junior engineers often read the alert as "the server is too small" and ask for an upgrade. The number is real, but it is describing waiting, not working.
You do not need special tooling. A handful of read-only commands answers most of it.
BASH
# Load average and how many CPUs the kernel sees
uptime; nproc

# r = runnable tasks, b = tasks in uninterruptible sleep, wa = iowait %
vmstat 1 5

# Tasks currently in D state and the kernel function they wait in
ps -eo pid,stat,wchan:32,comm | awk 'NR==1 || $2 ~ /^D/'

# Per-device latency and utilization (iostat is in the sysstat package)
iostat -x 1 3

# List NFS mounts without touching them, then check kernel complaints
findmnt -t nfs,nfs4
dmesg -T | grep -Ei 'blocked for more than|not responding'
In vmstat, compare the r and b columns. If r is consistently above the output of nproc and us plus sy is high, you have real CPU pressure. If r is small and b is large, the load is made of blocked tasks, and the rest of this guide is about finding what they are blocked on. The wa column (iowait) is the percentage of time a CPU was idle while there was outstanding disk I/O. It is a kind of idle time, not a kind of busy time. It helps, but read it carefully. On a machine with many cores, a few stuck tasks can produce a small iowait percentage because most CPUs have nothing at all to wait for. And depending on the kernel and code path, tasks blocked on NFS may not show up as iowait at all. Low wa with high b is a strong hint to look at network mounts. The ps line is usually the most telling. The wchan column shows the kernel function each D task is sleeping in. Names related to block I/O, page writeback, or filesystem journaling point at local storage. Names that mention nfs or rpc point at a network mount. On some kernels wchan only shows -, in which case root can read /proc/PID/stack for the same process to see the kernel call stack. One caution: commands like df or ls on a hung NFS mount will themselves hang in D state and add to the load. That is why the list above uses findmnt, which reads the mount table instead of querying each filesystem.
Storage is the likely cause when the blocked tasks wait in block or filesystem functions, iostat -x shows high wait times (the await or r_await/w_await columns, depending on sysstat version) on one device, and %util on that device stays near the top of its range. The common causes are fairly ordinary. A backup job or a large database dump saturates the disk. A RAID array is rebuilding. A disk is failing and retrying reads, which often leaves traces in dmesg and in SMART data. A database is flushing heavily because its memory settings push too much work to disk. A full or nearly full filesystem can also make writes slow in ways that surface here. On a VPS there is one more possibility: the virtual disk sits on shared storage, and the latency comes from the host side. From inside the guest, this looks the same as a slow local disk: high await, tasks in D, idle CPU. You cannot fix that from the guest. What you can do is collect iostat -x output over the period the problem happens and give it to your provider, because latency numbers with timestamps are much easier to act on than "the server feels slow". The fix belongs to the storage layer: reschedule or throttle heavy jobs, replace failing hardware, move hot data to faster disks, or tune the application that is producing the I/O. More CPU does nothing here.
A network mount is the likely cause when blocked tasks sit in NFS or RPC functions, findmnt shows NFS mounts, and dmesg contains lines like nfs: server ... not responding, still trying. Local disk numbers in iostat may look completely calm, which is often what confuses people. The behavior comes from how the mount was made. With a hard mount, which is the usual default for NFS, the client retries forever when the server stops answering. Every process that touches that path, including web workers, cron jobs, backup scripts, and monitoring agents that check disk space, joins the queue in D state. Load keeps climbing for as long as the server stays unreachable, and it can reach numbers that look absurd for the hardware. With a soft mount, the client gives up after its retries and returns an error to the application instead. That avoids the pile-up but can surface as I/O errors or, for writes, data that never reached the server. Neither option is free; it is a trade-off between hanging and failing. The kernel's hung task detector, if enabled, also logs task ... blocked for more than N seconds for processes stuck too long. The threshold is set by kernel.hung_task_timeout_secs and is commonly 120 seconds, but check your system. The fix here is on the network or the NFS server, not this machine. Check whether the server is up, whether the network path between client and server is working, and whether a firewall change blocked NFS traffic. Once the server answers again, the blocked tasks usually drain on their own and the load falls over the next few minutes as the averages catch up. Forcing an unmount or killing stuck processes is possible in some cases but riskier, since unwritten data can be lost and not every D task responds to signals. Treat that as a last resort and confirm what is on the mount first.
Sometimes the CPU really is the bottleneck and the idle view was just bad timing. Load average is smoothed over minutes, while top shows a few seconds. A short burst of work, such as a cron job that spawns many PHP processes at once, can lift the 1-minute load well after the burst has finished. The tell is the r column in vmstat. If it repeatedly runs above the core count during the problem window, b stays low, and us plus sy climbs when it happens, you have a capacity issue that just comes and goes. On a VPS, high steal time (st) is a separate case where the host is not giving your guest the CPU time it asks for. Here the options are the usual ones: spread scheduled jobs out, cap worker counts so they do not all start at once, optimize the code that bursts, or add CPU if the sustained load really needs it.
What you seeLikely causeWhere the fix lives
High b, wchan in block or filesystem code, high await in iostatSlow or saturated local storageDisk, I/O-heavy jobs, or the provider's storage
High b, wchan in NFS or RPC code, not responding in dmesg, calm local disksHung network mountNFS server, network path, mount options
High r above core count, high us/sy, low bReal CPU demand, possibly burstyWorkload scheduling, code, or more CPU
If you remember one thing, make it this: on Linux, load average is a count of tasks that want something, not tasks using the CPU. Before treating a high number as a capacity problem, run vmstat and the ps filter for D state. If the load is made of blocked tasks, follow wchan to the disk or the mount that is holding them, and fix it there.