·9 min read·Updated Aug 26, 2026

How to Tell If Your VPS Is Oversold: Steal Time, I/O and Real Tests

Measure CPU steal time, disk latency and cgroup throttling to find out if your VPS node is oversold — with commands, thresholds and honest limits.

"My VPS feels slow" is one of the hardest complaints to act on, because slowness can come from your own application, from the kernel, from a shared disk, or from a hypervisor running more virtual CPUs than the host can serve. This article shows how to separate those cases using measurements you can run in a few minutes, plus longer observations that catch problems that only appear at peak hours.

Direct answer

The fastest reliable signal that a KVM VPS is on a contended (oversold) node is sustained CPU steal time. If %steal averages above roughly 5% during your normal workload — and spikes into double digits — the hypervisor is unable to schedule your vCPUs on time and you are competing with other tenants.

Run this first:

vmstat 1 10

Look at the st column. Then confirm per-core with:

mpstat -P ALL 2 10

Zero or near-zero steal with slow application response means the bottleneck is elsewhere: disk latency, single-thread CPU speed, memory pressure, network, or your own code. Steal time alone doesn't prove abuse, and its absence doesn't prove a healthy node — the rest of this guide covers the gaps.

What "oversold" actually means

Every virtualization provider oversubscribes something. Selling 2 vCPU plans on a 32-thread host to more than 16 customers is normal and works fine, because most VPS instances are idle most of the time. Oversubscription becomes overselling when the aggregate demand regularly exceeds what the host can deliver, so tenants queue behind each other.

Three resources behave very differently here:

  • CPU is time-shared. Contention shows up as latency (steal time), not as errors. This is the most common form of overselling.
  • RAM is usually not oversold on serious KVM platforms, because the failure mode is ugly (swapping on the host, OOM kills, ballooning). If a provider advertises "dedicated RAM", this is what they mean.
  • Disk I/O is almost always shared. A single tenant running a heavy backup or database import on the same NVMe pool can raise your latency without touching your CPU numbers at all.

Knowing which one is degraded tells you whether to tune your stack, request a migration to another node, or change providers.

Step 1: confirm your virtualization type

Steal time is only meaningful under hardware virtualization. Container-based "VPS" products (OpenVZ, LXC, Virtuozzo) share the host kernel and generally report the host's view of CPU, so %steal stays at 0 even under severe contention.

systemd-detect-virt
lscpu | grep -i hypervisor
cat /proc/cpuinfo | grep -m1 'model name'

On a KVM instance, systemd-detect-virt returns kvm and you see a real CPU model (or a generic QEMU model if the provider masks it). On a container you'll typically get lxc, openvz or podman-style output. If you're in a container, skip to the I/O and throttling sections — the CPU accounting you see cannot be trusted for contention analysis. This is one practical reason full-root KVM instances, like the ones IronBalkans runs in Romania, are easier to audit: you get your own kernel, your own scheduler view, and honest counters.

Step 2: measure steal time properly

A ten-second sample proves almost nothing. Contention is bursty and follows the working hours of whoever shares your node. Collect data over at least 24–48 hours.

Install sysstat and let it record automatically:

apt install sysstat
sed -i 's/false/true/' /etc/default/sysstat
systemctl enable --now sysstat

Then read back history:

sar -u          # today, per 10-min interval
sar -u -f /var/log/sysstat/sa15   # 15th of the month

If you'd rather keep it minimal, a cron line is enough:

* * * * * date -u +\%FT\%TZ >> /var/log/steal.log; mpstat 1 5 | tail -2 >> /var/log/steal.log

How to read the results:

  • 0–1% steal: healthy node, no meaningful contention.
  • 1–5%: normal for busy shared platforms; usually invisible to applications.
  • 5–15% sustained: real contention. Latency-sensitive workloads (web request handling, game servers, real-time proxies) will feel it.
  • >15% sustained: the node is overcommitted for your workload. Tuning your app will not fix this.

Two caveats. First, steal time rises when you saturate your own vCPUs, because the hypervisor starts enforcing fair scheduling — so measure while your own load is moderate. Second, some hypervisor configurations do not expose steal accurately to guests, so a flat 0% under obvious slowness is itself suspicious.

Step 3: check for hard CPU throttling

Steal time is contention. Throttling is a policy: the provider caps your CPU at, say, 200% of one core regardless of host idle capacity. Both feel like "slow CPU" but the fix is different.

Inside your VPS, throttling imposed by the host is invisible in cgroup counters — but if you run containers yourself, check them:

cat /sys/fs/cgroup/cpu.stat

nr_throttled and throttled_usec growing means your own container limits are the constraint, not the node. On cgroup v1: /sys/fs/cgroup/cpu/cpu.stat.

To detect host-side capping, run a pure CPU loop and watch whether throughput drops after a few seconds of full load while steal stays low:

apt install sysbench
sysbench cpu --threads=$(nproc) --time=120 run

A score that starts high and settles to a plateau after 10–30 seconds, with %steal near zero and %user near 100%, points to burst credits or a fixed quota rather than noisy neighbours. Ask the provider directly what the CPU policy is — quota-based plans are legitimate as long as they're disclosed.

Step 4: benchmark single-thread and multi-thread CPU separately

Raw core count is the least useful number in a VPS spec sheet. A 4 vCPU plan on an old Xeon E5 can lose to 2 vCPU on a modern EPYC or Ryzen for most web workloads.

sysbench cpu --threads=1 --time=30 run
sysbench cpu --threads=$(nproc) --time=30 run
openssl speed -evp aes-256-gcm
7z b            # apt install p7zip-full

Compare single-thread to multi-thread scaling. If per-thread performance collapses as you add threads on an otherwise idle system, you're sharing physical cores (SMT siblings sold as separate vCPUs) or the node is busy. openssl speed is also a quick way to confirm AES-NI is exposed — important if you run TLS termination or encrypted volumes with LUKS, where a missing AES instruction set can cost you an order of magnitude in throughput.

Record the numbers on day one, right after deployment. They become your baseline; without one, you can only guess whether the node got worse.

Step 5: test disk latency, not disk throughput

dd if=/dev/zero of=test bs=1M count=1024 is the most misleading benchmark in hosting. It measures sequential writes into page cache and RAID write buffers and tells you nothing about the random I/O that databases, mail servers and container builds actually generate.

Use fio:

apt install fio

# 4K random read, queue depth 32 - the number that matters for databases
fio --name=randread --ioengine=libaio --direct=1 --bs=4k --iodepth=32 \
    --rw=randread --size=1G --runtime=60 --time_based --group_reporting

# 4K random write, sync-ish, single queue - worst case latency
fio --name=randwrite --ioengine=libaio --direct=1 --bs=4k --iodepth=1 \
    --rw=randwrite --size=1G --runtime=60 --time_based --group_reporting

Read the latency percentiles, especially p99, not just IOPS. On a healthy NVMe-backed platform, 4K random read p99 in the low hundreds of microseconds to a couple of milliseconds is reasonable. A p99 in the tens of milliseconds with modest IOPS means you're queuing behind other tenants or sitting on spinning disks.

For a continuous view of latency, ioping is lighter and safer to run on production:

apt install ioping
ioping -c 30 .

And to see whether your processes are the cause:

iostat -x 2 5      # look at %util, aqu-sz, r_await/w_await
iotop -oPa         # who is actually reading and writing

Also read the Pressure Stall Information counters, which the kernel exposes on 4.20+:

cat /proc/pressure/cpu
cat /proc/pressure/io
cat /proc/pressure/memory

The some avg60 value is the percentage of the last minute in which at least one task was stalled waiting for that resource. High IO pressure with low CPU usage is a clean signature of a storage bottleneck.

Step 6: memory and network sanity checks

For memory, watch for signs of host-side ballooning or your own overcommitment:

free -m
vmstat 1 5          # si/so columns: any sustained swap-in/out is bad
cat /proc/meminfo | grep -i commit
sysbench memory --threads=$(nproc) run

Sustained swap activity on a VPS with plenty of "free" memory reported can indicate the balloon driver reclaiming pages. Persistent swapping is a performance killer regardless of cause.

For network, test against a nearby endpoint you control, ideally another VPS:

apt install iperf3
iperf3 -c <your-other-server> -t 30 -P 4
mtr -rwzc 100 8.8.8.8

iperf3 measures capacity; mtr reveals packet loss and where it starts. Loss inside the provider's first two hops is theirs to fix. Loss that only appears at the far end of a long path is usually transit, not your VPS.

Common mistakes

Benchmarking once, at 03:00 UTC. Contention follows human schedules. A node that is idle at night can be saturated at 19:00 CET.

Comparing scores across providers with different CPUs. A sysbench number is only comparable against the same binary on the same distro and the same thread count. Otherwise you're measuring compilers and kernels.

Running fio with --size=100M. It fits in cache and produces fantasy IOPS. Use a working set larger than the RAM you have, or at minimum use --direct=1 as shown above.

Blaming the host for application problems. Before opening a ticket, verify with top, iotop and PSI that the stall is not caused by your own cron jobs, a runaway PHP-FPM pool, an unindexed query, or a backup process.

Assuming price implies quality. Cheap plans are not automatically oversold and expensive ones are not automatically clean. Only measurements tell you, which is why short-term plans and quick redeploys matter more than marketing pages. If you can spin up a node, benchmark it, and discard it without a long-term commitment — as with crypto-paid, instantly deployed instances — evaluating a platform costs an hour rather than a month.

Pros and cons of oversubscribed platforms

Honest trade-offs, because "never buy oversubscribed" is unrealistic advice:

In favour: oversubscription is what makes low-cost VPS plans possible at all. For development boxes, VPNs, bastion hosts, monitoring agents, IRC bouncers and low-traffic sites, a node with 3% steal time is completely fine and you save meaningfully over dedicated CPU pricing.

Against: anything latency-sensitive or CPU-bound suffers disproportionately. Video transcoding, CI runners, game servers, high-QPS databases and real-time proxies need either dedicated cores or a provider with conservative packing ratios. For these workloads, the cheapest plan is usually the most expensive one once you count wasted debugging time.

FAQ

Is high steal time always the provider's fault? No. If you keep all vCPUs pinned at 100%, the scheduler will throttle you toward your fair share and steal will rise. Measure at 30–60% of your own capacity to get a clean reading.

Can I see other tenants on the node? No, and you should be glad. Proper KVM isolation prevents guests from enumerating each other. You can only infer contention from your own counters.

What steal time should make me ask for a migration? Sustained double-digit steal across days, while your own load is moderate, is a reasonable case to raise with support. Include sar output with timestamps — a concrete graph gets a much faster response than "my server feels slow".

Does a higher vCPU count help on a contended node? Rarely. More vCPUs on the same busy host mostly increase scheduling overhead. A node change or a faster CPU generation helps more.

Do these tests work on containers? Disk, network and PSI tests do. CPU steal and cgroup-based conclusions may be unreliable because you don't own the kernel.

Conclusion

Diagnose in this order: confirm the virtualization type, watch steal time over days rather than seconds, rule out quota-based throttling, then measure random I/O latency percentiles instead of sequential throughput. Save a baseline the day you deploy, and keep sysstat running so that the next time performance degrades you have evidence rather than an impression.

That evidence is also the only fair basis for choosing a provider. Specs are marketing; p99 latency and steal time over a week are facts.

Written by IronBalkans. Last reviewed Aug 26, 2026.