What triggers this finding
A running EC2 instance whose average CPU utilization is below 5% over the last 30 days (from CloudWatch metrics).
Typical fix
Stop or terminate the instance if it is no longer needed. On paid plans, Parsivex generates AWS CLI scripts to stop or terminate safely — see Remediation script safety.
Example savings
Often 100% of the instance hourly cost — typically $10–$500+/month depending on instance type.
See also: Severity and savings estimates for how Parsivex calculates figures on your report.
How EC2 instance hours are billed
An on-demand EC2 instance bills for every second it spends in the running state, with a sixty-second minimum, at a rate fixed by its instance type and region. Nothing about that rate responds to load. A m5.xlarge sitting at 1% CPU and a m5.xlarge pinned at 95% produce identical line items. That is the entire mechanic behind this finding: the meter is wall-clock time, so the only way to reduce it is to stop the clock.
Parsivex prices the instance from a table of us-east-1 Linux on-demand rates converted to a month of 730 hours, and reports the whole figure as the estimated saving, because stopping or terminating removes all of it. Instance types the table does not price are skipped entirely rather than guessed at, so a scan will silently pass over exotic or very new families.
Two costs survive the stop and are deliberately outside the estimate. The root EBS volume keeps billing at its per-GB-month rate for as long as the instance exists in a stopped state — a stopped instance is not a free instance, it is an instance that has traded its hourly rate for a storage rate. And any Elastic IP still allocated to the account continues to accrue its own hourly charge, which is why a fleet of stopped instances often surfaces as an unused Elastic IP finding on the next scan.
Reading the utilization the detector reads
The finding fires when a running instance's average CPUUtilization over the last 30 days comes in under 5%. Parsivex pulls that from CloudWatch at a one-day period, so the number is an average of daily averages — a two-hour burst to 100% once a week barely moves it.
aws cloudwatch get-metric-statistics --namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
--start-time 2026-07-13T00:00:00Z --end-time 2026-08-12T00:00:00Z \
--period 86400 --statistics Average Maximum
Read both columns. The average is what triggers the finding; the maximum is what tells you whether the instance is genuinely dormant or merely spiky. Parsivex records both on the finding for the same reason.
Workloads that are quiet on purpose
CPU is the only utilization signal EC2 publishes without the CloudWatch agent installed, and plenty of real work does not show up in it. An instance can be saturated on memory, on disk, or on network while its CPU average sits near zero, and this detector cannot see any of that.
- Standby and failover capacity. A warm secondary earns its cost on the day the primary fails. Its steady state is 0% CPU and that is correct.
- Licence and identity servers. Domain controllers, licence daemons, and internal certificate authorities answer small requests rarely and matter enormously.
- Bastion and break-glass hosts. Used a handful of times a quarter, by design.
- I/O-bound and GPU work. A database replica streaming writes, or a GPU instance where the accelerator is busy and the host CPU is coordinating, both look idle here.
- Scheduled batch. A nightly ETL that runs for twenty minutes contributes roughly 1.4% to a monthly average even while pegged.
If the finding is wrong, resolve it as a false positive rather than leaving it open — the finding lifecycle keeps that decision from resurfacing on every scan.
What stopping and terminating cost you
Stopping is the reversible option and the right first move. The instance keeps its ID, its EBS volumes, its security groups, and its private address. Two things do not survive: any data on instance-store volumes is discarded, and an auto-assigned public IPv4 address is released and replaced with a different one on the next start. If something reaches this host by its public address, it will not find it again.
Terminating is final. The instance ID is gone, and root volumes marked DeleteOnTermination — the default — go with it. Snapshot anything you might want before you get there, and check that termination protection is not the only thing standing between an accidental script run and a lost disk.
The trap that catches people is Auto Scaling. An instance inside an Auto Scaling group is not yours to stop; the group notices the missing capacity and launches a replacement, so the instance comes back, the bill does not change, and the finding reappears next scan looking like a bug. If the instance carries an aws:autoscaling:groupName tag, the fix belongs in the group's desired capacity or its schedule, not on the instance.