CPU Steal on VPS: Measuring, Diagnosing, and Mitigating Hypervisor Contention

If you have ever watched top show 30% of your CPU as %st while your site crawls, you have met CPU steal. Steal is the time your virtual machine wanted to run but the hypervisor gave the physical CPU to another tenant instead. On a VPS, it is the single most common cause of mysterious slowdowns — and it is entirely outside your control. What you can control is detecting it, measuring it accurately, and choosing a plan that minimizes it. This guide shows you how to measure steal, how to distinguish it from other bottlenecks, and what mitigation strategies actually work.

What CPU Steal Actually Is

The hypervisor on a KVM, Xen, or VMware host time-slices each physical core between multiple virtual machines. When your neighbors saturate the host, your VM’s vCPUs queue for their turn, and the time spent waiting is recorded in the steal field of /proc/stat. It is surfaced by top (the %st column), vmstat (the st column), and mpstat (the %steal column). Understanding the difference between steal and similar metrics is critical:

MetricMeaningCauseActionable?
%st (steal)vCPU waiting for physical CPUHypervisor contentionSwitch provider or plan
%wa (iowait)CPU idle while waiting for I/ODisk or storage bottleneckUpgrade storage, tune I/O
%id (idle)CPU has nothing to doWorkload not CPU-boundApp-level optimization
%us/%syCPU busy with user/system codeApplication or OS overheadCode profiling, config tuning

Steal is not the same as iowait: iowait means your workload is waiting on disk or network, while steal means the CPU itself was taken away from you. On a healthy host, steal stays near zero; on an oversold one, it spikes during peak hours as neighboring VMs compete for the same cores.

How to Measure Steal Accurately

One-off measurements are misleading. Steal is a bursty metric — a single top snapshot may show 0% while the average over the last hour was 15%. Use these tools for a reliable picture:

Quick Check (Ad-Hoc)

# Real-time per-second samples over 30 seconds
vmstat 1 30
# Look at the 'st' column — sustained values above 5% are concerning

# Per-core steal percentages
mpstat -P ALL 5 6
# Sample every 5 seconds, 6 times

# Single-line average from /proc/stat
awk '/^cpu / {print "Steal: " $8 "%"}' /proc/stat

Long-Term Monitoring (Recommended)

Install sysstat and enable collection every 60 seconds. After a week, you can graph steal by hour and identify patterns:

sudo apt install sysstat
# Edit /etc/default/sysstat and set ENABLED="true"
# Edit /etc/cron.d/sysstat to collect every 2 minutes
sudo systemctl restart sysstat

# After collecting data, view hourly steal averages:
sar -u -f /var/log/sysstat/sa$(date +%d --date=yesterday) | awk 'NR>3 {print $1, $NF}'

Prometheus + Node Exporter (Production Stack)

For a permanent monitoring setup, node_exporter exposes the steal counter from /proc/stat as node_cpu_seconds_total{mode="steal"}. A Prometheus alert rule catches sustained contention:

# Alert when 5-minute average steal exceeds 5%
- alert: HighCPUSteal
  expr: avg by (instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) > 0.05
  for: 10m
  labels:
    severity: warning
  annotations:
    summary: "CPU steal {{ $value | humanizePercentage }} on {{ $labels.instance }}"

Diagnosis: Is Steal Actually Your Problem?

Not every slowdown is steal, and blaming the wrong metric wastes hours. Use this decision tree:

  • Is steal elevated (sustained > 5%, spiking above 20%)? If no, look elsewhere — database queries, network latency, or application code.
  • Is your application CPU-bound? Check %us + %sy in top. Steal matters only when your workload is actively waiting for CPU time. If your app is I/O-bound, high steal is irrelevant.
  • Does the slowdown correlate with steal spikes? Compare timestamps of slow requests against steal measurements. If your site is slow at 8 PM and steal spikes at 8 PM, the correlation is strong. If the site is slow all day but steal is only high at night, the problem is elsewhere.

Steal explains slow performance when three conditions all hold: steal is elevated, your application is CPU-bound at the time, and the slowdown correlates with the steal spikes rather than with disk or network metrics.

Mitigation Strategies

1. Confirm It Is Not You

Before blaming the host, rule out local issues: check that you are not swapping (high si/so in vmstat), that no runaway process is pegging a vCPU, and that your application is actually CPU-bound. A single misconfigured cron job or a memory leak that triggers swapping can look like steal but is entirely your problem to fix.

2. Pinpoint the Pattern

Log steal for at least a week. If it is consistently high (every hour, every day), the host is oversold — no amount of your own tuning will fix it. If it is a one-off spike, it may be a noisy neighbor that will move on, or a batch job on another VM that finishes. If it follows a predictable daily pattern (high during business hours, low at night), schedule your batch jobs and backups for the low-contention window.

3. Overprovision Slightly

If you cannot switch providers immediately, a practical workaround: a 2 vCPU plan with 40% steal delivers roughly the usable compute of a single core. Ordering one size up — 4 vCPUs instead of 2 — spreads the steal across more cores and reduces the effective impact. This is often cheaper than fighting contention with constant monitoring and support tickets.

4. Switch to a Provider with Dedicated vCPUs

This is the only fix that guarantees low steal. Providers selling “dedicated vCPU” or “vCPU pinning” plans isolate you from neighbors at the hypervisor level. The premium over shared vCPU plans is usually modest — often 20-40% more — and for a CPU-bound workload, it is worth every penny. The VPS provider comparison table at virtualserversvps.com notes which vendors publish their vCPU-to-core ratios and offer dedicated-core plans.

5. Benchmark Before You Migrate

Before moving to a new provider, run a steal stress test during their peak hours. Spin up a trial instance, install sysbench or stress-ng, and measure steal while the CPU is under load:

# Install stress-ng
sudo apt install stress-ng

# Run CPU stress for 10 minutes and log steal in parallel
stress-ng --cpu 0 --timeout 600 &
vmstat 5 120 | awk '{print strftime("%H:%M:%S"), $0}' > steal-log.txt

# After 10 minutes, check the average steal
awk '{sum+=$NF} END {print "Average steal: " sum/NR "%"}' steal-log.txt

If the candidate host shows < 2% average steal under full CPU load, you have found a provider worth moving to. If it shows 5%+ on a fresh trial instance, the host is already oversold — keep looking.

The Bottom Line

CPU steal is the one performance metric you cannot tune away. You can measure it, diagnose whether it is actually causing your slowdowns, and mitigate it with overprovisioning or scheduling — but the only honest fix is a provider that does not oversell. Compare dedicated vCPU options and transparent resource guarantees at our VPS provider comparison.

Leave a Reply