Back to blog
AWSBest PracticesCost OptimizationDatabasesOperations & Compliance

RDS Engine in Extended Support: What It Costs and How to Fix It

Learn what AWS RDS Extended Support charges mean, why outdated database engine versions cost you money, and how to upgrade safely with CLI and IaC examples.

TL;DR

This check flags RDS or Aurora instances running an engine version that has aged out of standard support and is now racking up AWS Extended Support fees. The fix is to upgrade the database to a supported major version before the per vCPU per hour charges pile up.

AWS does not let database engines run forever on a fixed version. Every major version of MySQL, PostgreSQL, MariaDB, and Aurora has a published end of standard support date. When that date passes, AWS keeps your instance running, but you are automatically enrolled in RDS Extended Support and billed extra for the privilege. The Lensix rds_extended_support check catches instances that have crossed this line so you can plan an upgrade before the bill grows.


What this check detects

The check inspects each RDS DB instance and Aurora cluster in your account and compares its engine version against the AWS standard support calendar. If the version has reached end of standard support, the instance falls into Extended Support and the check fails.

Concretely, it looks at the Engine and EngineVersion attributes returned by the RDS API and matches them against AWS published end of support dates. A failing result means one of two things:

  • The instance is already in Extended Support and accruing additional charges right now.
  • The instance is close enough to end of standard support that you should act before the deadline.

Note: Extended Support was introduced by AWS in 2024 to replace the old behavior of forced automatic upgrades. Instead of upgrading you without consent, AWS now keeps your old version patched for security issues and charges you for it. It buys you time, but it is not free.


Why it matters

This is primarily a cost and risk problem rather than a direct exploit vector, but the consequences are real.

The cost adds up fast

Extended Support is billed per vCPU per hour, and the rate increases over time. AWS uses a tiered model: the first year or two of Extended Support is at one rate, and later years cost roughly double. For a fleet of medium to large instances, this can quietly add thousands of dollars per month to your bill. Teams often discover the charge only when finance asks why the database line item jumped.

Warning: Extended Support charges apply per vCPU. A single db.r6g.4xlarge with 16 vCPUs accruing Extended Support fees costs significantly more than a small instance running the same outdated version. Large or numerous instances make this expensive quickly.

You are running on borrowed time

Extended Support is not indefinite. AWS publishes an end date for Extended Support too, usually around three years past end of standard support. Once that passes, AWS will force an upgrade on your behalf during a maintenance window, on its schedule rather than yours. An unplanned major version upgrade can break application compatibility, change query planner behavior, or deprecate features your code relies on.

Security and feature debt

Older engine versions miss out on performance improvements, new features, and certain security patches that only land in supported versions. While AWS does backport critical security fixes during Extended Support, you are still running aging software that your team has less institutional knowledge about over time.


How to fix it

The fix is to upgrade the engine to a version that is still under standard support. Do this carefully, because major version upgrades are not reversible.

Step 1: Identify the affected instances and target versions

List your instances and their current engine versions:

aws rds describe-db-instances \
  --query 'DBInstances[].{ID:DBInstanceIdentifier,Engine:Engine,Version:EngineVersion}' \
  --output table

Then find the valid upgrade targets for a given engine and version:

aws rds describe-db-engine-versions \
  --engine postgres \
  --engine-version 13.13 \
  --query 'DBEngineVersions[].ValidUpgradeTarget[].EngineVersion' \
  --output table

Pick a target version that is well within its standard support window so you are not repeating this exercise in six months.

Step 2: Test the upgrade on a clone

Never upgrade production first. Create a snapshot, restore it to a temporary instance, and run your application test suite against it.

# Snapshot the production instance
aws rds create-db-snapshot \
  --db-instance-identifier my-prod-db \
  --db-snapshot-identifier my-prod-db-preupgrade

# Restore the snapshot to a test instance
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier my-prod-db-upgrade-test \
  --db-snapshot-identifier my-prod-db-preupgrade

Then upgrade the test instance and validate. For major version PostgreSQL upgrades, check the AWS upgrade prerequisites, since extensions like pg_stat_statements sometimes need attention.

Tip: For PostgreSQL, run ANALYZE on all tables after a major version upgrade. The query planner statistics are not carried over, and skipping this step can cause sudden slow queries that look like the upgrade itself was the problem.

Step 3: Upgrade with a maintenance window

Danger: A major version upgrade rewrites the database and causes downtime. It cannot be rolled back without restoring from a snapshot. Schedule it during a maintenance window, confirm you have a fresh snapshot, and communicate the outage to stakeholders before running this.

Apply the upgrade immediately:

aws rds modify-db-instance \
  --db-instance-identifier my-prod-db \
  --engine-version 16.4 \
  --allow-major-version-upgrade \
  --apply-immediately

Or defer it to the next maintenance window by omitting --apply-immediately:

aws rds modify-db-instance \
  --db-instance-identifier my-prod-db \
  --engine-version 16.4 \
  --allow-major-version-upgrade

Step 4: Upgrading Aurora

For Aurora clusters, target the cluster rather than individual instances. To minimize downtime on large clusters, consider a blue/green deployment, which creates a synchronized copy on the new version and lets you switch over in under a minute.

aws rds create-blue-green-deployment \
  --blue-green-deployment-name my-cluster-upgrade \
  --source arn:aws:rds:us-east-1:123456789012:cluster:my-aurora-cluster \
  --target-engine-version 15.4

Note: Blue/green deployments keep the green environment in sync via replication, so the cutover is fast and reversible up until you switch over. This is the safest path for production databases that cannot tolerate a long maintenance window.


How to prevent it from happening again

The root cause is almost always that nobody owns tracking engine end of life dates. Automate it so the calendar does the watching for you.

Enforce supported versions in Terraform

If you manage RDS with Terraform, you can refuse to deploy or keep an unsupported version by validating against an allowlist. Keep the allowed versions in a variable and review it each quarter:

variable "allowed_engine_versions" {
  type    = list(string)
  default = ["16.4", "15.8", "14.13"]
}

resource "aws_db_instance" "main" {
  identifier     = "my-prod-db"
  engine         = "postgres"
  engine_version = "16.4"

  lifecycle {
    precondition {
      condition     = contains(var.allowed_engine_versions, self.engine_version)
      error_message = "Engine version ${self.engine_version} is not on the approved supported list."
    }
  }
}

Gate it in CI with policy as code

Use a tool like Open Policy Access or Checkov to fail pull requests that introduce an outdated version. A simple OPA Rego rule for a Terraform plan looks like this:

package rds

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_db_instance"
  version := resource.change.after.engine_version
  not allowed_versions[version]
  msg := sprintf("RDS instance uses unsupported engine version %v", [version])
}

allowed_versions := {"16.4", "15.8", "14.13"}

Run the Lensix check on a schedule

Policy as code catches new resources, but it will not flag an instance that was supported when deployed and aged out later. That is the gap continuous monitoring fills. Run rds_extended_support on a recurring schedule so an instance gets flagged the moment its version approaches end of life, giving you months of lead time to plan the upgrade.

Tip: Wire the failing check into a ticketing workflow so an upgrade task is created automatically when an engine version is within 90 days of end of standard support. Lead time turns a fire drill into routine maintenance.


Best practices

  • Stay one major version behind latest, not five. Upgrading from version 12 to 16 in one jump is risky. Regular smaller upgrades keep the gap manageable.
  • Build a recurring upgrade cadence. Treat database upgrades like patching, with a quarterly or biannual rhythm, rather than a one off emergency.
  • Always snapshot before upgrading. It is your only rollback path for a major version change.
  • Use blue/green deployments for production. They turn a multi minute outage into a quick cutover and give you a tested fallback.
  • Track the AWS end of support calendar. AWS publishes dates well in advance. Subscribe to RDS announcements and put the dates on a shared roadmap.
  • Tag instances with an owner. Orphaned databases are the ones that quietly accrue Extended Support charges because nobody is watching them.

Extended Support is a safety net, not a place to live. Catching these instances early with the rds_extended_support check keeps your bill predictable and puts upgrade timing back in your hands instead of AWS's.