RDS PostgreSQL 14 Extended Support Cost: The Bill That Starts March 1, 2027
AWS starts charging for PostgreSQL 14 on RDS on 1 March 2027, and it bills every standby and read replica, not just the primary. Here is the real cost math, the Terraform default that enrolled you without asking, and a twenty-week plan to avoid the line item.
By VVV Ops ·
Your PostgreSQL 14 fleet has about twenty weeks before it starts costing extra. The RDS PostgreSQL 14 extended support cost is not a penalty AWS threatens you with, it is a line item that appears automatically on 1 March 2027 and keeps growing for three years. We have watched teams discover it in an April bill, six weeks after the clock started, because nobody owned the upgrade and the Terraform defaults quietly opted them in. The surcharge is survivable. Paying it by accident, on a topology you never counted, is what turns a routine upgrade into a budget conversation.
Three dates, and only one of them bills you
PostgreSQL 14 has two end-of-life dates and they are months apart. The community ships its final 14 minor release on 12 November 2026 and then stops. AWS keeps 14 under standard support for another fifteen weeks, until 28 February 2027, then starts charging. From the RDS for PostgreSQL release calendar:
| Milestone | Date | |---|---| | Community end of life for PostgreSQL 14 | 12 November 2026 | | RDS end of standard support | 28 February 2027 | | Extended Support year 1 pricing starts | 1 March 2027 | | Extended Support year 3 pricing starts | 1 March 2029 | | RDS end of Extended Support | 28 February 2030 |
AWS is explicit that charges begin the day after the end of standard support date, which is why 1 March is the date to put in the calendar rather than 28 February.
There is a third date most teams miss, and it is much closer. Minor versions reach end of standard support on their own schedule, ahead of the major version. The release calendar puts 14.18 and 14.19 at 31 October 2026, roughly three weeks out, while 14.21 is already flagged NO_CREATE, meaning you cannot stand up new instances on it. So a team that reads "February 2027" and relaxes can still be running an unsupported minor next month. Check your minors before you plan the major.
What the bill actually looks like once you count the standbys
The published rate is per vCPU-hour, and the RDS for PostgreSQL pricing page gives $0.100 per vCPU-hour for years one and two in US East (Ohio), doubling to $0.200 from year three. Its own worked example is a db.r5.large at 2 vCPUs, which comes to $0.200 per hour.
The number that surprises people is not the rate, it is the count. AWS charges every instance running the out-of-support version. Standby instances in Multi-AZ deployments are billed. Read replicas are billed. Restore a snapshot into a new instance after the cutoff with the default enrollment and that instance is billed too. You are paying for a topology, not for one database.
Take a Multi-AZ primary of 8 vCPUs with two 8 vCPU read replicas, and assume a 730-hour month:
| Billed instances | vCPUs | Years 1 to 2 at $0.100 | Year 3 at $0.200 | |---|---|---|---| | Primary only | 8 | $584/mo | $1,168/mo | | Primary plus Multi-AZ standby | 16 | $1,168/mo | $2,336/mo | | Primary, standby, two read replicas | 32 | $2,336/mo | $4,672/mo |
Run that last row for the full window and the arithmetic is unkind. Twenty-four months at $2,336 is $56,064, then twelve months at $4,672 is another $56,064, for $112,128 on a single cluster you meant to upgrade. That is the shape of the decision: the surcharge is cheap enough to ignore for a quarter and expensive enough to fund the upgrade work several times over if you ignore it for a year.
Charges stop the moment you upgrade to a version under standard support, or delete the database. They are prorated, not annual, so a late upgrade still saves most of the money. AWS also notes that charges restart when your new target version eventually enters Extended Support itself, which is the argument for skipping ahead rather than stepping one version at a time.
Your IaC has probably already opted you in
There is an asymmetry here that catches people. In the RDS console, Enable RDS Extended Support is not selected by default. Through the CLI, the RDS API, and CloudFormation, the default is the opposite: if you say nothing, AWS enrolls you. The docs state the reasoning plainly, which is to keep your database available past the cutoff rather than force an upgrade on you.
The Terraform AWS provider inherits that default. The engine_lifecycle_support argument on aws_db_instance accepts open-source-rds-extended-support or open-source-rds-extended-support-disabled, and the provider documents the default as the former. So every database your modules created is enrolled unless somebody typed the opt-out.
# Illustrative. Resource and variable names are not from a real estate.
resource "aws_db_instance" "acme_orders" {
identifier = "acme-orders"
engine = "postgres"
engine_version = "16.15"
# Without this line the provider default enrolls the instance
# in paid Extended Support the day its major version leaves
# standard support.
engine_lifecycle_support = "open-source-rds-extended-support-disabled"
allow_major_version_upgrade = true
}
Do not set the opt-out as a blanket policy and walk away. Disabling enrollment is not a billing preference, it is an instruction to upgrade. AWS says that if you disable it on an instance already past its standard support end date, the instance automatically upgrades to the next supported major version, and that for an instance still inside standard support the upgrade happens on or shortly after the cutoff. An unattended major version upgrade of a production database, scheduled by AWS rather than by you, is worse than the surcharge. Set the opt-out only on databases you have already tested an upgrade path for.
Two more mechanics worth knowing. The setting is cluster-level, so members of a cluster always share it. And if you pass open-source-rds-extended-support-disabled when creating an instance after the cutoff date has passed, creation fails outright, which is a useful guardrail against someone restoring a 14 snapshot in 2028.
Find every instance that will bill you
Audit by version, not by name. Two commands do the work, and both return support dates straight from the API rather than from a blog post.
# Every PostgreSQL instance, its version, and its enrollment status.
aws rds describe-db-instances \
--query "DBInstances[?Engine=='postgres'].[DBInstanceIdentifier,EngineVersion,MultiAZ]" \
--output table
# Standard and Extended Support windows as AWS currently publishes them.
aws rds describe-db-major-engine-versions \
--query "DBMajorEngineVersions[?Engine=='postgres'].[MajorEngineVersion,SupportedEngineLifecycles]" \
--output json
The second command returns a SupportedEngineLifecycles array. Each entry carries a LifecycleSupportName of either open-source-rds-standard-support or open-source-rds-extended-support, with LifecycleSupportStartDate and LifecycleSupportEndDate. Diff that against your inventory on a schedule and the surcharge stops being a surprise. We put this in CI for clients rather than in a runbook, for the same reason we argue against manual drift checks in our Terraform anti-patterns post: an audit nobody runs is not a control.
To find out where you can actually go from 14, ask the API instead of guessing:
aws rds describe-db-engine-versions \
--engine postgres \
--engine-version 14.24 \
--query "DBEngineVersions[*].ValidUpgradeTarget[*].{EngineVersion:EngineVersion}" \
--output text
Pick the upgrade path before you pick the target version
RDS runs major version upgrades with pg_upgrade, and the upgrade documentation is candid about the consequences. A Multi-AZ instance deployment upgrades primary and standby at the same time and the database may be unavailable for several minutes. In-Region read replicas are upgraded along with the primary, and the primary waits for them, so your outage is as long as your slowest replica. On a Multi-AZ DB cluster, read replica replication state changes to terminated and you delete and recreate them by hand afterwards. You cannot revert; going back means restoring the pre-upgrade snapshot as a new database.
That last point drives the choice. RDS takes two snapshots during the upgrade, one before and one after, but only if your backup retention period is greater than zero. Confirm retention is non-zero before you start. An upgrade with no rollback snapshot is a gamble.
| Path | Downtime | Rollback | We would use it when | |---|---|---|---| | In-place pg_upgrade | Several minutes, longer with replicas | Restore the pre-upgrade snapshot into a new instance | Internal or batch databases with a real maintenance window | | Blue/green deployment | Typically under a minute at switchover | Blue environment is retained after switchover | Customer-facing databases, and anything where you want to test on production-shaped data first | | Logical replication to a new instance | Shortest, at the cost of building it yourself | Cut back to the original | Cross-version work RDS will not do in one hop, or a parallel platform migration |
For anything customer-facing we reach for blue/green deployments. RDS copies the whole topology, read replicas included, into a green environment named with a -green- suffix, lets you upgrade the engine version there, and keeps it in sync while you test. Switchover is typically under a minute and the old environment is renamed with an -old1 suffix rather than deleted, so rolling back means repointing at a database that is still running instead of restoring a snapshot. Two caveats. The green environment is read-only by default, and where RDS keeps it in sync with physical replication you cannot enable writes on it at all; only the logical replication variety lets you relax that, per-session, via default_transaction_read_only. Plan read-only testing and treat write testing as a bonus.
On target version, skip 15. Going 14 to 15 buys you until 29 February 2028, which is a year of runway for the same testing effort. The calendar gives 16 until 28 February 2029, 17 until 28 February 2030, and 18 until 28 February 2031. Unless an extension pins you, go to 17 or 18 and buy four years.
Budget the testing, not the upgrade
The upgrade itself is a modify call. The work is proving your application survives it, and that work does not compress. Extensions are where major version upgrades fail: a pinned extension version that does not exist on the target, or an extension the target no longer ships, will stop pg_upgrade before it starts. Inventory them first with SELECT * FROM pg_extension; on every database in the instance, not just the one you think matters.
Then plan for the parts teams routinely forget. Query plans change across major versions, so a plan that was fine on 14 can regress on 17 under the same statistics. Client drivers and connection poolers need their own compatibility pass. Any logical replication slot, whether feeding a warehouse or a CDC pipeline, has to be rebuilt.
Our rough split on client engagements is that the upgrade window is a fraction of the effort and the application regression testing is most of it. We will not put a precise multiplier on that, because it depends entirely on how many extensions and how much raw SQL you carry. What we will say is that teams who scope only the maintenance window are the ones who end up paying the surcharge, because they discover the extension problem in February and have no time left.
A dated plan to 1 March 2027
Twenty weeks is comfortable if you start now and tight if you start in January.
- This month, inventory every PostgreSQL instance and its minor version. Anything on 14.18 or 14.19 needs a minor upgrade before 31 October 2026 regardless of your major version plan.
- By end of November, pick the target version and audit extensions on every database. This is the step that finds the blocker.
- By end of December, stand up a blue/green deployment or a restored clone on the target version and run your regression suite against it.
- In January, run the upgrade on staging, measure the actual switchover time, and write the rollback step down.
- In February, upgrade production. Leave the final two weeks empty, because something will slip.
- Audit
engine_lifecycle_supportacross your modules once production is done, and set the opt-out only on the databases you have upgraded.
If the date slips, the surcharge is the fallback rather than the failure. Paying $0.100 per vCPU-hour for two months while you finish testing is a reasonable trade. Paying it for two years because the project lost its owner is not, and that is the outcome worth defending against.
This post covers one engine. The same version-support surcharge now appears across managed services, and we wrote up the Kubernetes version of it in Kubernetes extended support cost, which goes into how the surcharge behaves across clouds. If the RDS line item is already on your bill, our AWS cost optimization tactics covers the rest of the bill it is hiding in.
When to Get Help
Bring someone in when the inventory turns up more than a handful of instances, when an extension has no path to your target version, or when the database is customer-facing and nobody has run a blue/green switchover before. Those are the cases where the cost of a bad upgrade exceeds three years of the surcharge.
We run PostgreSQL major version upgrades on AWS as scoped engagements: inventory and extension audit, target version decision, blue/green rehearsal with your regression suite, then the production switchover with a written rollback. If you have PostgreSQL 14 in production and no date on the calendar yet, get in touch and we will start with the audit.