Back to tutorials
Tutorial

Server Disk I/O Troubleshooting Tutorial (2026): Find the Real Cause of High iowait on a Hosting VPS

Server disk I/O troubleshooting tutorial for 2026: pinpoint high iowait, slow disks, and noisy processes on your hosting VPS.

By Anurag Singh
Updated on Jun 25, 2026
Category: Tutorial
Share article
Server Disk I/O Troubleshooting Tutorial (2026): Find the Real Cause of High iowait on a Hosting VPS

High CPU usage is noisy. High iowait is worse because it can mislead you. The server may look “idle” while requests stall, SSH feels sticky, and backups drag.

This server disk i/o troubleshooting tutorial gives you a repeatable workflow. You’ll pinpoint what’s blocking reads and writes on a hosting VPS or dedicated server. You’ll fix it with evidence, not guesswork.

The steps below assume Ubuntu 24.04/26.04 LTS or Debian 12/13 on a typical web stack (Nginx/Apache + PHP-FPM, WordPress, cron jobs, and backups).

If you want a clean baseline to compare against, start with a HostMyCode VPS. You control the storage class there. You can also scale IOPS as your workload grows.

What you’ll collect (and why it matters)

Most disk I/O incidents fall into one of four buckets:

  • Hot files (logs, cache, sessions) creating constant small writes
  • One noisy process (backup, malware scanner, search index) hogging the device
  • Bad I/O patterns (sync writes, excessive fsync, poor buffering, wrong temp-dir)
  • Real storage limits (IOPS cap, degraded volume, filesystem errors)

Your job is to capture a short, high-signal snapshot. Identify the device, the process, the access pattern, and the time window.

With that information, you can make the smallest change that removes the bottleneck.

Step 0: Confirm it’s disk latency (not network or CPU)

Start by checking whether the symptoms match disk pressure. On a busy web node, iowait often looks like this:

  • Web requests queue up while CPU stays moderate
  • SSH commands take 1–3 seconds before output appears
  • PHP-FPM workers sit “running” longer than they should
  • Load average climbs without a matching CPU spike
# Quick 60-second snapshot
uptime
vmstat 1 10

In vmstat, focus on:

  • wa (I/O wait): sustained > 10% under normal traffic is a warning sign
  • r (run queue): high r with low CPU often means tasks are blocked on I/O
  • bi/bo (blocks in/out): shows read/write pressure

If the disk is bloated and constantly writing (runaway logs, old backups, cache churn), fix that first.

Use this VPS cleanup workflow so you’re not debugging a server that’s simply out of breathing room.

Step 1: Identify the busy device and the type of I/O

On Linux, iostat is the fastest way to see device saturation and latency. It also shows whether reads or writes dominate.

sudo apt-get update
sudo apt-get install -y sysstat

# Extended stats every second
iostat -x 1 15

Find the device that hosts your web workload. It’s often /dev/vda, /dev/sda, or an NVMe like /dev/nvme0n1.

Start with these fields:

  • %util: near 100% for long stretches usually means the device can’t keep up
  • await: average latency. Consistently > 20–30ms on SSD/NVMe workloads is usually painful for web apps
  • r/s, w/s: IOPS. Lots of tiny writes often hurt more than a few large ones
  • svctm is not reliable on many modern kernels; lean on await and %util

If %util is low but await is high, suspect the storage backend. Common causes include burst credits exhausted, throttling, contended storage, or a degraded volume.

If this is production and you need predictable I/O, moving to dedicated servers or a higher-tier managed VPS hosting plan is often the practical fix.

Step 2: Prove which mount is slow (web root, database, backups)

Before you chase processes, map your storage layout. You need to know where the slow I/O happens.

  • /var/www (web files, uploads)
  • /var/lib/mysql or /var/lib/mariadb (database data)
  • /var/log (logs and audit trails)
  • /tmp or /var/tmp (PHP sessions, temp files, compression)
df -hT
lsblk -f
findmnt -D

If you “have a separate backup disk,” verify it’s actually a separate device. A common gotcha is a backup directory living on the same saturated root volume.

Step 3: Catch the process doing the damage (without guessing)

Use iotop to answer “who is writing right now?” in real time.

sudo apt-get install -y iotop
sudo iotop -oPa

Watch for:

  • High “DISK WRITE” from rsync, tar, gzip, php, mysqld, or a security scanner
  • High “DISK READ” from log analyzers, crawlers, or malware scans
  • Repeatable spikes every minute (or every 5/15 minutes) that line up with cron

After you spot the spike, match it to a schedule. On hosting VPS nodes, I/O storms often come from stacked jobs.

WordPress cron, backups, and log rotation can all kick off together.

# System cron
ls -la /etc/cron.*

# Root crontab
sudo crontab -l

# Per-user crons
sudo ls -la /var/spool/cron/crontabs 2>/dev/null || true

If you want a cleaner view of what happened during the spike window, centralize logs and correlate timestamps.

HostMyCode covers that here: centralize logs with rsyslog + TLS.

Step 4: Distinguish “too many small writes” from “big sequential jobs”

The fix depends on the I/O pattern. Separate these two cases before you tune anything:

  • Small random writes: high writes/s, small request sizes, sessions/logs/cache churn, latency climbs fast
  • Large sequential writes: fewer ops/s with higher MB/s, usually backups, compression, exports
# Show per-disk throughput
sar -d 1 10

On high-traffic sites, access logging alone can burn a surprising amount of small-write IOPS.

If logs look like the culprit, the usual mitigations are:

  • Use buffered logging and rotate more often
  • Put logs on a separate volume (best) or ship them off-box quickly
  • Dial down verbosity for static assets

On Nginx, turning off access logs for hot static paths can be an immediate win:

# /etc/nginx/sites-available/example.conf
location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg)$ {
  access_log off;
  expires 30d;
}
sudo nginx -t && sudo systemctl reload nginx

Step 5: Check filesystem health and kernel messages

If disk latency suddenly gets worse, check kernel logs early. Reset events, I/O errors, and filesystems flipping read-only will show up there.

sudo dmesg -T | egrep -i "(error|i/o|reset|nvme|ext4|xfs|blk)" | tail -n 80

If you see ext4 errors, plan a controlled check during a maintenance window. On a VPS, that often means rescue mode or attaching the disk elsewhere.

On dedicated servers, you can schedule downtime and run fsck safely.

Treat filesystem errors as an incident, not a tuning task.

Step 6: Fix the most common hosting I/O killers

These fixes show up repeatedly on web hosting systems. Only apply changes that match what you saw in iostat and iotop.

A) Backups are saturating the disk during peak hours

If backups run during busy traffic, you’ll feel it right away. Reads, compression, and writes compete with the web workload.

  • Move backup windows to off-peak.
  • Lower priority so user traffic wins.
  • Write backups to a separate volume or offsite target.
# Run a heavy job with low I/O priority and lower CPU priority
ionice -c2 -n7 nice -n 10 /usr/local/bin/backup-script.sh

If you want an offsite setup with encryption and retention, follow this Restic + S3 backup tutorial. It’s structured to avoid “backup storms” that kneecap performance.

B) PHP sessions and cache are writing constantly

Session writes can melt disks on busy WordPress and WooCommerce sites. This is even more likely when you host multiple sites on one VPS.

  • Confirm your session path and which volume it’s on.
  • Make sure session cleanup runs and isn’t stuck.
  • Move sessions to Redis on high-traffic setups (where appropriate).
# Find PHP session configuration
php -i | egrep -i "session.save_handler|session.save_path"

For WordPress, Redis object caching can cut repeated reads and smooth bursty traffic.

If you want to implement it and verify real cache hits, use: Redis object cache setup for WordPress.

C) Log growth and rotation are thrashing the disk

Logrotate can cause short spikes. Constant log writes are usually the bigger problem.

Reduce verbosity first. Then tune rotation.

Quick diagnostic:

sudo du -sh /var/log/* 2>/dev/null | sort -h | tail -n 20
sudo lsof +L1 | head -n 30   # deleted but still-open files

If you find large “deleted” log files still held open, restart the service. That releases the file handles and stops writes to nowhere.

sudo systemctl restart nginx || true
sudo systemctl restart apache2 || true
sudo systemctl restart php8.3-fpm || true

D) Your disk is full (or close enough to behave badly)

Once ext4 gets very full, performance drops fast. At ~95% usage, latency spikes and background writes get messy.

df -h /
  • Free space immediately (old backups, caches, runaway logs).
  • Add monitoring and alerting so it doesn’t sneak up on you again.

If you recently hit “No space left on device,” don’t delete random directories in a panic. Use a structured approach: disk space troubleshooting for hosting VPS.

Step 7: Validate with a controlled benchmark (optional, but useful)

After changes, measure again. Avoid destructive benchmarks on production disks.

Use read-only tests or small, isolated files. Run them during low traffic.

# Basic read test (uses OS cache unless you flush; use carefully)
sudo hdparm -Tt /dev/vda 2>/dev/null | cat

For a safer latency check, use fio with a small test file in a dedicated directory. Do not use your database directory.

sudo apt-get install -y fio
mkdir -p /root/fio-test
cd /root/fio-test

# 60s random read test, 1G file
fio --name=randread --filename=testfile --size=1G --direct=1 --rw=randread --bs=4k --iodepth=32 --numjobs=1 --time_based --runtime=60 --group_reporting

Pay attention to avg latency and IOPS consistency. If results swing wildly between runs, you may be hitting an I/O ceiling or contended storage.

In that case, a plan with predictable disk performance is often the cleanest fix.

Step 8: Put guardrails in place (so this doesn’t repeat next week)

Once the server is stable, add two guardrails: monitoring and change control.

These guardrails stop the same failure from resurfacing after the next plugin update or schedule change.

Monitoring checklist

  • Alert on disk usage: warn at 80%, critical at 90%
  • Alert on I/O wait: sustained wa > 10% for 5–10 minutes
  • Alert on disk latency if your tool supports it (avg await)
  • Track top talkers: backups, cron, and web logs during spikes

If you want a practical dashboard with low overhead, pair this with: Netdata monitoring + alerts.

Operational checklist

  • Stagger cron jobs so backups, rotations, and batch tasks don’t overlap.
  • Throttle heavy scripts with ionice and nice.
  • Keep backups off the root disk whenever possible.
  • Review log verbosity quarterly (Nginx/Apache/app logs).
  • Test restores and rebuilds, not just “backup success”.

Quick triage table (symptom → likely cause → first action)

SymptomLikely causeFirst action
High iowait, iostat %util ~100%Device saturationiotop to find process; throttle backups; reduce log writes
Latency spikes at exact timesCron overlap / scheduled batchMap cron; reschedule; add ionice
Disk 95% full, everything “hangs”Filesystem pressureFree space safely; restart services holding deleted files
dmesg shows reset/I/O errorsUnderlying disk/backend issuesOpen incident; plan fsck; consider migrating to better storage
Lots of small writes, web traffic highAccess logs/sessions/cacheDisable access logs for static; move sessions/cache strategy

Summary: a repeatable workflow for high iowait

High iowait gets easier to fix when you stop tuning blindly and start collecting proof. Confirm the stall with vmstat. Identify the device and latency with iostat. Then name the process with iotop.

From there, choose the right fix. That might mean rescheduling jobs, throttling heavy tasks, reducing log churn, or upgrading storage.

If your workload has outgrown burstable IOPS—or you’re hosting multiple revenue sites—put it on storage that behaves predictably under load.

A HostMyCode VPS is a solid baseline, and managed VPS hosting is a good fit if you want an experienced team handling ongoing performance and stability work.

If you’re dealing with random latency spikes or recurring high iowait, your storage tier (or your maintenance routines) probably doesn’t match the workload. Run this workflow on a HostMyCode VPS for clean visibility and predictable resources, or choose managed VPS hosting if you want to hand off day-to-day troubleshooting and the guardrails that prevent repeat incidents.

FAQ

What is iowait, and why does it make my server feel slow?

iowait is CPU time spent waiting for disk I/O to complete. Requests stall because processes block on reads/writes, even if CPU usage looks fine.

Which metric matters more: %util or await?

Use both. %util tells you the device is busy; await tells you latency is hurting users. For web workloads, sustained high await is usually what you feel.

Can I fix high iowait without upgrading the server?

Often, yes. Stagger cron, throttle backups with ionice, reduce log writes, and stop writing backups to the root disk. If you’re consistently saturating storage under normal traffic, an upgrade is the honest fix.

Is it safe to run fio on a production server?

Only if you keep the test small, use a dedicated directory, avoid database paths, and run during low traffic. Never run destructive tests against a live volume.

What’s the fastest way to find which process is causing disk writes?

sudo iotop -oPa is the quickest high-signal view. Pair it with iostat -x 1 so you see both the culprit and the device behavior.