Skip to content

EC2 t3/t4g instance suddenly slow: CPU credits and the burstable surprise

Why a t3 or t4g EC2 instance slows to a crawl under sustained load: how CPU credits work, how to read CPUCreditBalance, and when unlimited mode quietly bills you instead.

When a t3 or t4g instance that ran fine for weeks suddenly crawls — requests queuing, load average climbing, CPU pinned at a weirdly low ceiling — the usual culprit is an exhausted CPU credit balance. Burstable instances earn credits at a fixed rate and spend them whenever CPU runs above a small baseline; sustained load drains the tank, and in standard mode the instance is then throttled to its baseline no matter how hard the workload pushes. In unlimited mode there is no slowdown — instead you get a surplus-credit charge on the bill. Either way, the graph that explains everything is CPUCreditBalance.

What’s happening

The t family (t3, t3a, t4g) sells you a fraction of a CPU with the right to burst. Each size has a baseline — a percentage of a full vCPU it may use continuously (roughly 10% per vCPU on a t3.micro, rising with size) — and earns CPU credits at a constant hourly rate. One credit equals one vCPU-minute at 100%. Run below baseline and credits accumulate, up to a cap of about 24 hours of earnings; run above it and credits burn.

What happens at zero depends on the credit mode:

  • Standard mode: the hypervisor caps the instance at its baseline. From inside, the box feels broken — top shows modest CPU while everything is slow, because the OS cannot see the external throttle. Steal time (%st in top) often rises. This is the “surprise slowdown.”
  • Unlimited mode (the default for t3/t3a/t4g at launch, unless your account or template overrides it): the instance keeps bursting on surplus credits. If average utilization stays above baseline over a rolling 24 hours, the surplus is billed per vCPU-hour. Performance stays fine; the surprise moves to the invoice. A t3 that persistently bursts in unlimited mode can end up costing more than the m-family instance you avoided buying.

Both behaviours are working as designed. The t family is priced for spiky, mostly-idle workloads — dev boxes, low-traffic sites, cron runners. A steady-load service on a t instance is a mispriced m instance with extra steps.

What to check first

  • CPUCreditBalance trend over two weeks. A sawtooth that recovers is healthy; a slow decline to zero explains the slowdown and tells you roughly when it started.
  • Credit mode. Standard or unlimited decides whether you are debugging latency or a bill.
  • What changed when the drain began — a deploy, a traffic step, a runaway process, a cryptominer. Credit exhaustion is a symptom; something started eating CPU.
  • Steal time inside the guest. Sustained %st on a t instance at zero balance is the throttle made visible.
  • Whether the workload was ever a burst workload. If average CPU sits above baseline every day, the instance family is wrong, not the tuning.

How to verify

Pull the credit metrics (5-minute periods; these are standard instance metrics, no agent needed):

aws cloudwatch get-metric-statistics \
  --namespace AWS/EC2 --metric-name CPUCreditBalance \
  --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
  --start-time 2026-06-27T00:00:00Z --end-time 2026-07-04T00:00:00Z \
  --period 3600 --statistics Average

Do the same for CPUCreditUsage, CPUSurplusCreditBalance, and CPUSurplusCreditsCharged — the last one is the direct “unlimited mode is billing you” signal. In the console, EC2 > Instances > (instance) > Monitoring charts all four next to CPUUtilization, which is the fastest way to see utilization flatline exactly at baseline when the balance hits zero.

Check the credit mode:

aws ec2 describe-instance-credit-specifications \
  --instance-ids i-0123456789abcdef0

Inside the guest, top or mpstat 5 showing rising %st alongside low usable CPU corroborates external throttling. The full credit table per size lives in the EC2 documentation.

The fix

  1. Stabilize first if production is hurting: switch the instance to unlimited mode — it takes effect immediately, no restart:

    aws ec2 modify-instance-credit-specification \
      --instance-credit-specifications 'InstanceId=i-0123456789abcdef0,CpuCredits=unlimited'

    This trades throttling for a metered surplus charge; it is a tourniquet, not the treatment.

  2. Find and fix what is eating the credits. Profile the box: a runaway worker, a log-shipping loop, an unindexed query pushed to the app tier. If the drain began with a deploy, the deploy is your suspect.

  3. Right-size if the load is real and steady. Sustained utilization above baseline means the workload has outgrown burstable economics — move to m7g/m6i (general purpose) or c7g/c6i (compute-heavy). Compute Optimizer’s rightsizing recommendations will usually flag exactly this pattern.

  4. Move up within the t family if the load is still spiky but bigger — a larger t size earns credits faster and has a higher baseline, which is often cheaper than leaving unlimited surplus charges running.

  5. Decide the credit mode deliberately per environment. Standard for dev boxes where throttling is a harmless signal; unlimited for production t instances where you accept metered bursts — with a billing alarm to match.

When this is the wrong move

Do not reflexively flee the t family after one credit incident. For genuinely spiky workloads, a t4g is dramatically cheaper than an always-on m instance, and Graviton t4g pricing makes it one of the best value instances AWS sells. Equally, do not “fix” credit exhaustion by scripting stop/start cycles or juggling instances — launch credits on new t2 instances were the old trick, and t3/t4g accounts get limited launch credits precisely to stop that game. Fix the workload or fix the family.

Common mistakes

  • Reading CPUUtilization alone and concluding “CPU is only at 20%, it must be the network” — 20% may be the baseline ceiling.
  • Not knowing which credit mode is in effect, so throttling gets debugged as an app bug, or surplus charges get debugged as a billing error.
  • Benchmarking on a fresh t instance with a full credit balance and sizing production from those numbers.
  • Running databases or queue workers on t instances because they idle in staging — production load profiles differ, and the data tier fails ugliest under throttle.

Prevention

  • A CloudWatch alarm on CPUCreditBalance below roughly 20% of the size’s maximum, wired into the same alerting path as your CloudWatch alarm baseline.
  • An alarm on CPUSurplusCreditsCharged above zero for standard-intent instances that someone flipped to unlimited and forgot.
  • A quarterly review of average CPU on every t instance: anything living above baseline gets a family change, not a bigger tank.
  • Document the credit-mode decision in the launch template so it survives instance replacement.

Burstable instances are a contract: mostly idle, occasionally fast. Hold up your side and they are the cheapest compute on AWS; break it and you get throttled or billed, whichever mode you picked. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.