Skip to content

RDS engine version upgrades: minor vs major, and how to rehearse the major ones

How RDS minor and major engine version upgrades differ, what actually causes downtime, and a rehearsal runbook that makes a major version upgrade boring instead of terrifying.

Minor RDS engine upgrades stay within the same major version family, rarely break applications, and are safe to automate into the maintenance window. Major upgrades change engine behaviour — SQL semantics, defaults, the query planner — and the only way to make one safe is to rehearse it on a restored copy of production first. The upgrade itself is one API call; the work is everything you do before it.

What’s happening

A minor upgrade (PostgreSQL 16.3 to 16.4, MySQL 8.0.36 to 8.0.37) ships bug fixes and CVE patches with a compatibility promise. If AutoMinorVersionUpgrade is enabled, RDS applies it during a maintenance window after AWS designates that version for auto-upgrade. Expect a short outage even so: on a Multi-AZ instance deployment, RDS upgrades the primary and standby together for engine changes, so Multi-AZ does not hide the downtime the way it does for hardware failure. Multi-AZ DB clusters (the two-readable-standby topology) can do rolling minor upgrades with much shorter interruption.

A major upgrade (PostgreSQL 15 to 16, MySQL 5.7 to 8.0) is never automatic. You trigger it, RDS runs engine prechecks, takes a snapshot before and after, and converts the data dictionary — pg_upgrade under the hood for PostgreSQL. Three things routinely surprise teams: the instance needs a parameter group from the new family, so your tuned parameters must be ported, not carried over; PostgreSQL optimizer statistics are not migrated, so queries run badly until you ANALYZE; and read replica handling differs by engine — RDS for PostgreSQL upgrades replicas with the primary, while for MySQL you upgrade replicas yourself, normally before the primary.

There is also a clock running. When an engine version reaches community end of life, RDS moves it to Extended Support and bills for it per vCPU-hour — staying on an old version is no longer free. The version calendar lives in the engine release notes at https://docs.aws.amazon.com/rds/.

What to check first

  • Current version and auto-upgrade flag — know exactly what you run and whether AWS will move it without you.
  • Valid upgrade targets — you often cannot jump straight to the latest major; RDS defines allowed paths.
  • Parameter group — custom or default? Custom means you have a diff to port to the new family. See parameter group tuning for production Postgres / MySQL.
  • Read replicas — how many, which versions, and which engine rules apply to them.
  • Pending maintenance — an already-scheduled OS or certificate action can collide with your window.

How to verify

aws rds describe-db-instances --db-instance-identifier prod-db \
  --query 'DBInstances[0].[EngineVersion,AutoMinorVersionUpgrade,DBParameterGroups[0].DBParameterGroupName,ReadReplicaDBInstanceIdentifiers]'

aws rds describe-db-engine-versions --engine postgres --engine-version 15.8 \
  --query 'DBEngineVersions[0].ValidUpgradeTarget[].{Version:EngineVersion,Major:IsMajorVersionUpgrade}' \
  --output table

aws rds describe-pending-maintenance-actions

In the console, RDS > Databases > (instance) > Maintenance & backups shows the maintenance window and any pending actions. After a rehearsal upgrade, the Logs & events tab shows precheck failures — for MySQL 5.7 to 8.0 they land in an upgrade log you can read directly there.

The runbook

  1. Restore a rehearsal copy. Restore the latest snapshot (or a point-in-time restore) into a new instance in a non-production account or VPC, same instance class and storage as production. An empty test database proves nothing — upgrade duration and precheck failures scale with real data.
  2. Run the upgrade on the copy and time it. aws rds modify-db-instance --db-instance-identifier rehearsal-db --engine-version 16.4 --allow-major-version-upgrade --apply-immediately. Record wall-clock downtime; that number is what you tell the business.
  3. Fix what the prechecks find. Orphaned tables, unsupported extension versions, reserved-word collisions (MySQL 8.0 reserved rank and groups), incompatible parameters. Fix in production before the real run so the precheck passes clean.
  4. Port the parameter group. Create a parameter group in the new family, diff your customizations against the new defaults — some parameters change meaning or disappear between majors — and attach it as part of the upgrade.
  5. Test the application against the copy. Point a staging app at the rehearsal instance and run your key workflows, not just SELECT 1. Planner changes show up here, nowhere else.
  6. Schedule the real run. Take a manual snapshot immediately before (RDS takes its own, but yours is under your retention rules). For MySQL, upgrade replicas first; for PostgreSQL, expect replicas to follow the primary.
  7. Post-upgrade tasks immediately. On PostgreSQL run ANALYZE on every database, then update extensions with ALTER EXTENSION ... UPDATE. Watch p95 latency and CPU for 48 hours against your pre-upgrade baseline.

When this is the wrong move

If the business cannot absorb the measured downtime from step 2 — for large busy instances a major upgrade can take well over an hour — an in-place upgrade is the wrong tool. Use an RDS blue/green deployment instead: the upgrade happens on a synchronized copy and the switchover takes about a minute. And if the driver is only a CVE, check whether a minor release in your current family already carries the fix before planning a major.

Common mistakes

  • Assuming Multi-AZ means zero-downtime upgrades. Engine upgrades on Multi-AZ instance deployments take both nodes at once.
  • Skipping ANALYZE after a PostgreSQL major upgrade, then spending a day chasing a “slow database” that just has no statistics.
  • Leaving the instance on the default parameter group of the new family, silently losing years of tuning.
  • Rehearsing on a small synthetic dataset, so the production run takes five times longer than promised.

Prevention

  • Keep AutoMinorVersionUpgrade on for everything except the most change-sensitive workloads, and know your maintenance window.
  • Track engine EOL dates yearly; Extended Support fees turn procrastination into a line item.
  • Keep parameter groups in infrastructure-as-code so porting to a new family is a reviewed diff, not archaeology.
  • Rehearse one major upgrade per year even if none is due — the muscle matters more than the version.
  • If an upgrade goes sideways in production, open a case early; AWS Support can see engine-side state you cannot.

A major version upgrade run this way is a scheduled non-event: the prechecks pass because you already fixed them, the downtime matches the rehearsal, and the app was tested against the new planner weeks ago. 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.