24 mins read

How to Diagnose a Slow VPS With Low CPU and RAM Usage: The I/O Wait Problem

When a VPS feels slow but top shows CPU mostly idle and plenty of free memory, the bottleneck is usually storage. The number to look at is %wa in top, the I/O wait figure, which measures how much time the CPU spends doing nothing because it is waiting for a disk operation to finish. A server can be 90 percent idle by CPU percentage and completely unusable in practice.

The diagnosis takes three commands and about five minutes. The fix depends entirely on what those commands reveal, and adding more CPU or RAM to an I/O bound server changes nothing at all, which is why diagnosing before upgrading matters here more than almost anywhere else in server administration.

Why Can a VPS Be Slow When CPU and RAM Usage Look Normal?

A VPS can be slow with idle CPU and free memory because processes are blocked waiting on storage rather than competing for processor time. CPU percentage measures work being done. It does not measure work that cannot start because the data it needs has not arrived from disk yet.

Understanding the difference between CPU usage and I/O wait

In top, the CPU line breaks down into several states, and most people read only the first two. The one that matters here is wa:

top CPU line on an I/O bound server

%Cpu(s):  3.1 us,  1.8 sy,  0.0 ni, 17.4 id, 77.2 wa,  0.0 hi,  0.5 si,  0.0 st

Read that honestly and the picture is clear. User processes are using 3.1 percent. The system is truly idle only 17.4 percent of the time. The remaining 77.2 percent is the CPU sitting still, blocked, waiting for the disk. A monitoring dashboard reporting only CPU used would show roughly 5 percent on this server and suggest everything is fine.

The st column at the end is worth noting too. That is steal time, the percentage of time the hypervisor gave your virtual CPU to another guest. On a VPS, a persistently high st value points at contention on the host rather than anything inside your own server.

How applications can be blocked while waiting for storage operations

A process waiting on disk enters uninterruptible sleep, shown as state D in process listings. It is not consuming CPU, it cannot be interrupted, and it will not proceed until the kernel returns its data. List them directly:

Processes stuck in uninterruptible sleep, waiting on disk

$ ps -eo state,pid,comm | awk ‘$1 ~ /D/’

D    2841 mysqld

D    3120 php-fpm

D    3122 php-fpm

Three processes in D state on a small server is enough to make every page load feel sluggish, and none of them appear as CPU consumers in any dashboard.

Why memory availability does not guarantee fast application performance

Free memory means the server is not swapping, which is genuinely useful to know, but it says nothing about whether the disk can keep up with requests. A database reading from a slow virtual disk is bound by storage latency regardless of how much RAM sits unused alongside it.

There is a related trap. Memory that looks free may actually be needed for filesystem cache, and a server with too little cache re-reads the same data from disk repeatedly, turning a memory shortage into what looks like a storage problem.

How load average can reveal problems that CPU percentage misses

Linux load average counts processes in uninterruptible sleep alongside processes actually running, which is a meaningful difference from most other operating systems. A load average far above the CPU core count on a server showing low CPU utilization is close to a definitive I/O wait signature:

Load average of 14.82 with only one process actually running

top – 03:12:44 up 62 days,  9:41,  1 user,  load average: 14.82, 11.36, 7.05

Tasks: 241 total,   1 running, 240 sleeping,   0 stopped,   0 zombie

One running process and a load average near 15 means roughly fourteen processes are queued in D state waiting on storage. On a two core VPS that is a server in serious trouble, despite CPU graphs that would look almost flat.

Why storage latency can become the hidden VPS bottleneck

Storage is the one resource on a VPS that is genuinely shared in a way CPU and RAM usually are not. Allocated CPU cores and memory are yours. The physical disks underneath your virtual disk are frequently serving other guests at the same time, which means your storage performance can change without anything changing on your server at all.

How Can You Check Whether I/O Wait Is Causing the VPS Slowdown?

Confirm I/O wait with four tools in sequence: top for the overall %wa figure, iostat for per device latency and queue depth, vmstat for blocked process counts, and iotop to identify which specific process is generating the disk activity.

Checking CPU and I/O wait with top or htop

Start with top and read the CPU line as shown above. Anything above roughly 10 percent wa sustained is worth investigating; anything above 30 percent means storage is the dominant constraint on that server. In htop the same figure appears in the CPU meters, though it is easy to miss without enabling detailed CPU time display in the setup menu.

This is one practical advantage a VPS has over shared hosting when something goes wrong. Root access means you can run these diagnostics yourself rather than describing symptoms to a support team and waiting for someone else to look at the underlying metrics.

Using iostat to examine disk utilization and latency

iostat comes from the sysstat package, installed with apt install sysstat on Debian and Ubuntu or dnf install sysstat on RHEL and AlmaLinux. Two flags matter: -x for extended statistics, and -y to skip the first report.

iostat showing write latency and a deep queue

$ iostat -xy 1 3

Device   r/s    rkB/s  r_await  w/s      wkB/s    w_await  aqu-sz  %util

vda      20.0   160.0  0.40     2980.0   23840.0  12.40    36.96   99.80

That first report iostat prints is an average since boot, not a current sample, and reading it is the single most common iostat mistake. The -y flag suppresses it so the first block you see reflects the last second.

In the sample above, w_await of 12.40 milliseconds and aqu-sz of nearly 37 are the meaningful numbers. Requests are queuing up faster than the device can clear them. Note also that the workload adds to exactly 3,000 IOPS, and a suspiciously round flat number like that usually indicates a provider imposed IOPS cap rather than hardware reaching its physical limit.

Understanding what %util does and does not tell you

%util is the percentage of time the device had at least one request in flight. On a traditional single queue rotational disk that made it a reliable saturation indicator. On NVMe and modern SSDs it is misleading, because a device serving 64 requests in parallel reports 100 percent while still operating well below its capacity.

The iostat man page states this directly: for devices serving requests in parallel, such as RAID arrays and modern SSDs, %util does not reflect their performance limits. Read r_await, w_await, and aqu-sz instead, and treat a high %util on NVMe as a prompt to look closer rather than a conclusion.

One version caveat worth knowing before comparing output against older documentation: sysstat 12 renamed avgqu-sz to aqu-sz and removed svctm entirely. Check which version you are running with iostat -V if the column names do not match what you expected.

Using vmstat to identify system-level I/O pressure

vmstat gives a compact system wide view, and the column to watch is b, the count of processes blocked waiting for resources:

vmstat with 14 blocked processes and 77 percent I/O wait

$ vmstat 1 5

procs ———–memory———- —swap– —–io—- -system– ——cpu—–

 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

 1 14      0 412992  18432 2104320    0    0   112 24408 1842 3021  3  2 18 77  0

A persistently non zero b column is the clearest single confirmation that storage, not CPU, is the constraint. The si and so columns are worth checking in the same output, since sustained swap activity there points at a memory shortage that is generating disk I/O as a side effect.

Using iotop to identify processes generating heavy disk activity

Neither top nor iostat can attribute disk activity to a specific process. iotop can, and it needs root:

iotop showing mysqld and an rsync backup competing for the same disk

$ sudo iotop -oPa

Total DISK READ: 1.42 M/s | Total DISK WRITE: 23.61 M/s

  PID  PRIO  USER  DISK READ  DISK WRITE  COMMAND

 2841  be/4  mysql    412.0 K    18.92 M  mysqld

 4102  be/4  root       2.1 M     3.40 M  /usr/bin/rsync –server

The -o flag shows only processes actually doing I/O, -P aggregates by process rather than thread, and -a shows accumulated totals rather than instantaneous rates. If iotop is unavailable, pidstat -d 1 from the same sysstat package gives comparable per process data in a format that logs cleanly.

Comparing I/O metrics with application response times

Metrics alone do not prove causation. Line up the timestamps: if slow page loads and support complaints cluster at the same times as the iostat latency spikes, the connection is real. If the two do not correlate, the I/O wait may be a genuine but secondary issue and the actual bottleneck lies elsewhere.

What Causes High I/O Wait on a VPS?

High I/O wait typically traces to one of five causes: database activity exceeding what the storage can serve, backups or cron jobs running heavy sequential reads, runaway logging or temporary file churn, a poorly behaved application generating excessive disk operations, or contention with other guests on the underlying host storage.

Heavy database read and write activity

Databases are the most frequent single cause. An unindexed query forcing a full table scan turns what should be a handful of reads into thousands, and a query that would complete instantly against an indexed column can saturate a virtual disk when run repeatedly. Enabling the MySQL slow query log is usually the fastest way to find the specific queries responsible.

Large backups and scheduled maintenance jobs

Backups read large volumes of data sequentially and are one of the most common reasons a server shows heavy I/O wait on a predictable schedule. The iotop sample earlier shows exactly this scenario, an rsync backup running while the database is still serving live traffic.

Application level backup tools have the same effect. A plugin backing up a large WordPress site through Softaculous or a similar tool generates real disk load, and scheduling several client sites to back up simultaneously multiplies it.

Excessive logging and temporary file activity

Debug logging left enabled after troubleshooting is a quiet, persistent source of write I/O. PHP error logs, application debug output, and verbose access logs all write synchronously, and a site generating errors on every page view writes to disk on every page view.

WordPress plugins or applications generating excessive disk operations

Certain plugin categories are reliably disk heavy: security scanners performing full filesystem scans, backup plugins, broken link checkers, and any plugin storing large volumes of data in the database. A scan crawling every file on the server will show clearly in iotop while it runs.

On a VPS running cPanel, the per account resource usage view is a useful cross reference here, since it narrows the problem to a specific account before you start reading process lists. In WHM the same data is visible across every account on the server at once, which is faster when you are trying to identify which of several sites is responsible.

Storage contention on the underlying virtualization platform

If your own workload cannot account for the observed I/O, the cause may be outside your server entirely. Other guests on the same host can saturate shared storage, and from inside your VPS this appears as high latency with modest request rates, a combination worth recognizing because no amount of optimization on your side resolves it.

How Can You Tell Whether the Problem Is Your VPS or the Storage Backend?

Distinguish the two by comparing your measured I/O against your actual workload. High latency alongside heavy activity from your own processes means the problem is yours. High latency with light activity, or throughput pinned at a flat round number, points at the backend or a provider imposed cap.

Comparing disk utilization with application workload

The diagnostic question is proportionality. If iotop accounts for the bulk of the observed I/O through your own processes, the workload is the problem and optimization will help. If iostat shows high await while iotop shows very little process activity, something outside your server is consuming the storage capacity.

What You ObserveLikely CauseWhere the Fix Lies
High await, your processes busy in iotopYour own workload exceeds storage capacityOptimize, then upgrade if needed
High await, iotop nearly idleContention or throttling outside your VPSProvider ticket
IOPS pinned at a flat round numberProvider IOPS cap, not hardware limitPlan change or provider
High %util, low await, low aqu-szNormal parallel device behaviourNo action needed
High wa plus high st in topHost level contention affecting CPU tooProvider ticket

Table 1. Reading the combination of metrics rather than any single number is what separates a workload problem from a platform problem.

Looking for consistently high storage latency

Latency expectations differ enormously by storage type, which is why a number that is alarming on one platform is normal on another.

Storage TypeTypical LatencyRough IOPS Range
Traditional HDD5 – 15 ms75 – 200
SATA SSD0.5 – 2 ms10,000 – 90,000
NVMe SSD0.05 – 0.5 ms100,000+

Table 2. Indicative latency and IOPS by storage class. Virtualized storage adds overhead, so a VPS will not match bare metal figures, but the relative gap between classes holds.

Against that reference, a w_await of 12 milliseconds is unremarkable for a rotational disk and genuinely poor for anything built on NVMe storage, where sub millisecond figures are the expectation rather than a best case.

Identifying sudden versus sustained I/O spikes

A spike at 03:00 every day is almost certainly a scheduled job, and crontab -l plus a check of /etc/cron.d will usually name it within a minute. Sustained elevation through business hours points at ordinary workload exceeding capacity. Sudden onset with no corresponding change on your side is the pattern most consistent with a backend problem.

Checking whether multiple workloads compete for the same storage

On a server hosting several sites, stagger anything heavy. Backups, cron jobs, and scans scheduled for the same moment compound, and separating them by even an hour frequently resolves a problem that looked like insufficient storage performance. This matters especially on a reseller hosting account where multiple client sites may default to the same backup window without anyone having chosen it, and more again on a master reseller setup where sub accounts add another layer of scheduling nobody is coordinating centrally.

When to contact the VPS provider about underlying storage performance

Open a ticket once you have evidence rather than an impression. Include the iostat output showing await and aqu-sz, the iotop output showing your own processes are not responsible, the time window, and the steal time figure if elevated. That set of four converts a vague performance complaint into something a provider can actually investigate against host metrics.

How Can You Reduce I/O Wait Without Immediately Upgrading the VPS?

Reduce I/O wait by eliminating unnecessary disk activity first: fix the queries causing table scans, move backups off peak, turn off debug logging, add caching so fewer requests reach the disk, and resolve any swap activity, then re-measure after each change rather than applying everything at once.

Identifying and reducing unnecessary disk-heavy processes

Work down the iotop list in order. The single heaviest writer is usually responsible for a disproportionate share of the problem, and addressing it alone often brings %wa back to acceptable levels without touching anything else.

Optimizing database queries and storage activity

Enable the slow query log, let it collect for a day of normal traffic, and examine what it captures:

Finding the queries that are actually hitting the disk

— In MySQL / MariaDB

SET GLOBAL slow_query_log = ‘ON’;

SET GLOBAL long_query_time = 1;

— Then inspect a suspect query’s execution plan

EXPLAIN SELECT * FROM wp_postmeta WHERE meta_value = ‘example’;

An EXPLAIN output showing type: ALL and a large rows figure means a full table scan, and adding an appropriate index typically reduces the disk reads for that query by orders of magnitude. On WordPress sites, an oversized wp_postmeta table is a frequent culprit.

Reviewing backup schedules and resource usage

Move backups to genuinely low traffic hours and stagger them if several run. Where the backup tool supports it, throttling its I/O rate lets it take longer while leaving capacity for live traffic, which is almost always the better trade for a production server.

Reducing excessive application and system logging

Turn off debug logging in production. In WordPress that means confirming WP_DEBUG is false in wp-config.php. Check that logrotate is actually rotating and compressing logs rather than letting single files grow without limit, and reduce verbosity on any application logging every request by default.

Checking swap activity and memory pressure

Swap activity generates disk I/O directly, which means a memory problem can present as a storage problem. If si and so in vmstat show sustained activity, the fix is memory, either freeing it by tuning process counts or adding more, not storage optimization:

Memory exhausted and swap heavily in use, generating disk I/O

$ free -h

               total        used        free      shared  buff/cache   available

Mem:           3.8Gi       3.4Gi       118Mi        62Mi       302Mi       164Mi

Swap:          2.0Gi       1.7Gi       312Mi

Note the available column rather than free. Linux uses spare memory for cache by design, so a low free figure is normal and not itself a problem. An available figure this low, with swap heavily used, is a real memory shortage.

Monitoring I/O after each optimization

Change one thing, then measure. Applying five optimizations simultaneously leaves you unable to tell which one helped, which matters when the problem returns in three months and you need to know what actually worked. Re-run iostat -xy 1 5 after each change and record the before and after figures.

When Should You Upgrade the VPS Storage or Move to a Different Plan?

Upgrade when optimization has genuinely been done and I/O wait remains high under normal workload, when the storage type is fundamentally mismatched to the application, or when the provider confirms you are hitting an IOPS ceiling the current plan cannot raise.

Recognizing persistent storage bottlenecks

The honest test: after the queries are indexed, backups moved, logging reduced, and swap resolved, does iostat still show high await and a deep queue during ordinary traffic? If yes, the workload legitimately exceeds the storage and more optimization will produce diminishing returns.

Understanding the difference between IOPS and storage capacity

These are independent and frequently confused. Capacity is how much data fits. IOPS is how many operations per second the storage can serve. A 500 GB volume that is 5 percent full can still be completely saturated on IOPS, and buying more space does nothing for it.

Some providers scale IOPS with volume size, which makes a larger volume an indirect performance upgrade. Others apply a flat cap per plan tier. Knowing which model applies determines whether more space would help at all.

When NVMe storage can make a practical difference

NVMe helps most for workloads dominated by small random reads and writes, which describes database driven sites almost exactly. The latency gap in Table 2 is not a marginal improvement; it is roughly an order of magnitude against SATA SSD and two against rotational disk.

It helps least for workloads that are already CPU bound or genuinely limited by network throughput. This is the same diagnostic discipline as everywhere else in this article: NVMe fixes storage latency, and if storage latency is not your constraint it will not change your response times. SkyNetHosting’s VPS plans are built on NVMe by default, which removes the storage class question but not the need to confirm storage is actually the bottleneck first.

Why adding CPU or RAM may not solve an I/O bottleneck

This is the most expensive mistake available here. A server at 77 percent I/O wait has CPU capacity going unused, and doubling the cores gives it more capacity to sit idle with. The upgrade path has to match the constrained resource.

Additional RAM is the partial exception, since more memory means more filesystem cache and fewer reads reaching the disk. If the workload is write heavy rather than read heavy, even that offers limited relief.

There is a related judgement call about direction. If the underlying problem turns out to be contention on shared infrastructure rather than your own workload, a semi-dedicated server or a fully dedicated server addresses the cause directly, since neither shares storage with other guests the way a VPS does. A larger VPS on the same contended host may not change anything.

What storage-performance metrics to ask a VPS provider about

Ask specific questions and expect specific answers. Vague reassurance about fast SSD storage is not an answer to any of these.

Question to AskWhy It Matters
What storage type backs this plan?NVMe, SATA SSD and HDD differ by orders of magnitude
Is there an IOPS cap per plan or per volume?A flat cap explains suspiciously round throughput numbers
Is storage local to the host or network attached?Network storage adds latency that local storage does not
How is noisy neighbour contention managed?Determines how exposed you are to other guests
Does a larger plan raise IOPS or only capacity?Decides whether upgrading actually helps performance

Table 3. Five questions that establish whether a plan can support your workload, before you commit to it.

The order matters more than any individual step: measure with top and iostat, attribute with iotop, optimize what you control, and only then consider hardware. Where the diagnosis does point to storage, the class of storage underneath the plan is what determines the ceiling. See what NVMe VPS hosting actually provides before deciding an upgrade is the fix.

Leave a Reply

Your email address will not be published. Required fields are marked *