Introduction
In this blog, we’ll walk through:
- How Azure PostgreSQL upgrades work
- Why does Terraform recreate the server
- Multiple migration strategies
- The exact steps I followed to upgrade PostgreSQL 11 → 13 safely
Existing Setup
My environment had the following characteristics:
- Azure Database for PostgreSQL – Flexible Server
- PostgreSQL version: 11
- SKU: Burstable B1ms (1 vCore, 2 GiB RAM)
- Storage: 32 GiB
- Region: Central US
- Provisioned using Terraform
- Mixed environments: Some with public access, some with VNet integration
- Firewall rules restricted to specific IPs
Terraform snippet (simplified):
Important Reality: No In-Place Major Version Upgrade
- You cannot upgrade PostgreSQL 11 → 13 on the same server
- Changing version = "13" in Terraform:
- Deletes the existing PostgreSQL 11 server
- Creates a brand-new PostgreSQL 13 server
- All data is lost unless you migrate or restore it manually
Why This Upgrade Looks Simple — and Why It Isn’t
At first glance, the upgrade appears trivial: version = "13"
- Azure treats PostgreSQL major versions as immutable
- Terraform maps this to a ForceNew operation
- Automated backups are tied to the old server lifecycle
- Configuration and data do not carry over
What Actually Happens (Timeline)
Understanding the timeline helps avoid surprises:T-0: PostgreSQL 11 running
- Applications connected
- Data live
- Automated backups available
T-1: Terraform version updated
- version = "11" → version = "13"
- Plan shows forces replacement
T-2: Terraform apply
- PostgreSQL 11 server is deleted
- Databases and backups disappear
T-3: PostgreSQL 13 server created
- Empty server
- Default parameters
- No firewall rules
- No databases
T-4: Manual restore
- Data restored
- Configuration reapplied
- Applications reconnect
Available Upgrade Approaches
Step 1: Take a Backup
I used pgAdmin 4 with a custom format backup.Why Custom format?
- Includes schema + data
- Best compatibility across versions
- Works cleanly with pg_restore
Step 2: Upgrade PostgreSQL Version via Terraform
In Terraform, change the code: version = "13"Important: This destroys the PostgreSQL 11 server and creates a new PostgreSQL 13 server with the same name.
Run:
terraform plan
terraform apply
This immediately destroys the PostgreSQL 11 server and creates a new PostgreSQL 13 server with the same name.
Step 3: Restore the Database to PostgreSQL 13
This:
- Recreated the database
- Restored schema and data
- Worked cleanly from v11 → v13
Step 4: Server Parameters & Configuration
Azure applies default server parameters when a new PostgreSQL server is created.
Key learning:
- Server parameters are NOT automatically migrated
- If you changed parameters manually in the portal, you must reapply them
Step 5: VNet-Integrated Environments
For servers with VNet integration:
- No public endpoint exists
- Local pgAdmin / pg_dump won’t connect
- Use Azure DMS inside the VNet
- Use a VM or jumpbox
- Temporarily enable public access
We temporarily enabled public access with strict /32 firewall rules and disabled it immediately after migration.
/32 firewall rules and disabled it immediately after migration.Step 6: Validate & Cutover
After restoring:
- Verified tables, row counts, and extensions
- Tested application connectivity
- Updated connection strings where required
- Disabled public access again for private environments
Cost Considerations
- PostgreSQL B1ms server: ~$25/month
- Temporary overlap or migration time: a few dollars
- Azure DMS (Standard): Often free for migration scenarios
- Overall upgrade cost: minimal
Key Takeaways
- Azure PostgreSQL major upgrades are not in-place
- Terraform recreates the server when version changes
- Always backup before upgrading
- Server parameters must be reapplied
- For VNet setups, plan connectivity carefully
- PostgreSQL supports direct jump from 11 → 13
Final Thoughts
Upgrading PostgreSQL on Azure requires careful planning, but with the right approach, it can be a predictable and safe process.If you’re using Terraform:
- Treat major version upgrades as rebuild + restore
- Automate as much as possible
- Test in lower environments first
