Aurora Blue/Green in Practice — How RDS Proxy Changes Switchover Downtime
Table of Contents
Introduction
In Part 1, we observed 26 seconds of downtime and 6 connection failures during an Aurora PostgreSQL Blue/Green Switchover using psql. DNS TTL of 60 seconds was the primary bottleneck. In Part 2, the AWS JDBC Driver's BG plugin achieved zero connection failures — but it's limited to Java (JDBC).
What about Python, Go, Node.js, and other non-Java languages? On April 9, 2026, AWS announced RDS Proxy support for Blue/Green Deployments. With RDS Proxy, applications always connect to the proxy endpoint, so when the database endpoint's DNS changes during switchover, the application's DNS cache is unaffected. The proxy internally detects the switchover and redirects connections to the Green environment. It works regardless of language or driver.
This article measures RDS Proxy switchover downtime using the same psql-based approach from Part 1:
- How much downtime does RDS Proxy switchover produce?
- What error patterns occur during switchover?
- Where does it rank compared to direct connection and the JDBC BG plugin?
See Using RDS Proxy with Blue/Green Deployments for official documentation.
Test Environment
| Item | Value |
|---|---|
| Region | ap-northeast-1 (Tokyo) |
| Engine | Aurora PostgreSQL 16.9 (Blue) → 17.6 (Green) |
| Instance class | db.r6g.large |
| Configuration | Writer × 1 (no Reader) |
| RDS Proxy | PostgreSQL engine family, no TLS |
| VPC | Default VPC (3 AZs) |
| Client | EC2 (Amazon Linux 2023, t3.medium) + psql 16.12 |
| Test interval | 1 second (INSERT + inet_server_addr(), 200 iterations) |
| Switchover timeout | 300 seconds (default) |
Prerequisites:
- AWS CLI configured (
rds:*,ec2:*,iam:*,secretsmanager:*permissions) - psql (PostgreSQL client)
Skip to results if you only want the findings.
Before diving into setup, there's a critical constraint to be aware of when combining RDS Proxy with Blue/Green Deployments.
Proxy Target Must Be Registered Before Blue/Green Creation
There's a critical constraint when combining RDS Proxy with Blue/Green Deployments: the Blue cluster must already be a target of the proxy before creating the Blue/Green Deployment. You cannot add a Blue cluster to an RDS Proxy after a Blue/Green Deployment has been created for that cluster.
This is documented in the official docs. If you already have an RDS Proxy setup, this isn't an issue. But when building both from scratch, pay attention to resource creation order.
Additionally, RDS Proxy with Blue/Green Deployments is not supported for Aurora Global Databases.
Environment Setup
Aurora cluster, RDS Proxy, and EC2 creation steps
Replace the following placeholders with your own values throughout the commands.
ACCOUNT_ID— AWS account IDVPC_ID— VPC IDSG_ID— Security group ID (created below)SUBNET_1,SUBNET_2,SUBNET_3— Subnet IDs in different AZs (3 required)SUBNET_ID— Subnet ID for the EC2 instancePASSWORD— Database master passwordSECRET_ARN— Secrets Manager secret ARNAL2023_AMI_ID— Amazon Linux 2023 AMI IDPROXY_ENDPOINT— RDS Proxy endpoint
Security Group
aws ec2 create-security-group \
--description "SG for Blue/Green + RDS Proxy verification" \
--group-name bg-proxy-verify-sg \
--vpc-id $VPC_ID
# Self-referencing rule (Proxy ↔ Aurora ↔ EC2 PostgreSQL traffic)
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--port 5432 \
--protocol tcp \
--source-group $SG_IDDB Subnet Group
aws rds create-db-subnet-group \
--db-subnet-group-name bg-proxy-verify-subnet \
--db-subnet-group-description "Subnet group for BG Proxy verification" \
--subnet-ids '["$SUBNET_1","$SUBNET_2","$SUBNET_3"]'Secrets Manager Secret
RDS Proxy retrieves database credentials from Secrets Manager.
aws secretsmanager create-secret \
--name bg-proxy-verify-secret \
--secret-string '{"username":"postgres","password":"$PASSWORD"}'Custom Cluster Parameter Group
Blue/Green Deployments require logical replication.
aws rds create-db-cluster-parameter-group \
--db-cluster-parameter-group-name bg-proxy-verify-cpg \
--db-parameter-group-family aurora-postgresql16 \
--description "Cluster PG with logical replication"
aws rds modify-db-cluster-parameter-group \
--db-cluster-parameter-group-name bg-proxy-verify-cpg \
--parameters '[{"ParameterName":"rds.logical_replication","ParameterValue":"1","ApplyMethod":"pending-reboot"}]'Aurora Cluster and Instance
aws rds create-db-cluster \
--db-cluster-identifier bg-proxy-verify \
--db-cluster-parameter-group-name bg-proxy-verify-cpg \
--db-subnet-group-name bg-proxy-verify-subnet \
--engine aurora-postgresql \
--engine-version 16.9 \
--master-username postgres \
--master-user-password $PASSWORD \
--vpc-security-group-ids '["$SG_ID"]'
aws rds create-db-instance \
--db-cluster-identifier bg-proxy-verify \
--db-instance-class db.r6g.large \
--db-instance-identifier bg-proxy-verify-w1 \
--engine aurora-postgresqlAfter the instance becomes available, reboot to apply the logical replication setting.
aws rds reboot-db-instance --db-instance-identifier bg-proxy-verify-w1RDS Proxy Creation and Target Registration
Create an IAM role with Secrets Manager access.
aws iam create-role \
--role-name bg-proxy-verify-role \
--assume-role-policy-document '{
"Version":"2012-10-17",
"Statement":[{
"Effect":"Allow",
"Principal":{"Service":"rds.amazonaws.com"},
"Action":"sts:AssumeRole"
}]
}'
aws iam put-role-policy \
--role-name bg-proxy-verify-role \
--policy-name SecretsManagerAccess \
--policy-document '{
"Version":"2012-10-17",
"Statement":[{
"Effect":"Allow",
"Action":["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],
"Resource":"$SECRET_ARN"
}]
}'Create the proxy and register the Aurora cluster as a target.
aws rds create-db-proxy \
--db-proxy-name bg-proxy-verify \
--engine-family POSTGRESQL \
--auth '[{"AuthScheme":"SECRETS","SecretArn":"$SECRET_ARN","IAMAuth":"DISABLED"}]' \
--role-arn arn:aws:iam::$ACCOUNT_ID:role/bg-proxy-verify-role \
--vpc-subnet-ids '["$SUBNET_1","$SUBNET_2","$SUBNET_3"]' \
--vpc-security-group-ids '["$SG_ID"]'
# After proxy becomes available, register the target
aws rds register-db-proxy-targets \
--db-proxy-name bg-proxy-verify \
--db-cluster-identifiers '["bg-proxy-verify"]'Wait for TargetHealth.State to become AVAILABLE (~5 minutes).
Blue/Green Deployment
Create a parameter group for the Green environment and create the deployment.
aws rds create-db-cluster-parameter-group \
--db-cluster-parameter-group-name bg-proxy-verify-cpg-17 \
--db-parameter-group-family aurora-postgresql17 \
--description "Cluster PG for PG17"
aws rds create-blue-green-deployment \
--blue-green-deployment-name bg-proxy-verify-bgd \
--source arn:aws:rds:ap-northeast-1:$ACCOUNT_ID:cluster:bg-proxy-verify \
--target-engine-version 17.6 \
--target-db-cluster-parameter-group-name bg-proxy-verify-cpg-17Green environment provisioning took ~32 minutes. Wait for status to become AVAILABLE.
EC2 Instance
Create an SSM-accessible EC2 instance and install psql.
# Create IAM role and instance profile for EC2
aws iam create-role \
--role-name bg-proxy-verify-ec2-role \
--assume-role-policy-document '{
"Version":"2012-10-17",
"Statement":[{
"Effect":"Allow",
"Principal":{"Service":"ec2.amazonaws.com"},
"Action":"sts:AssumeRole"
}]
}'
aws iam attach-role-policy \
--role-name bg-proxy-verify-ec2-role \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
aws iam create-instance-profile \
--instance-profile-name bg-proxy-verify-ec2-profile
aws iam add-role-to-instance-profile \
--instance-profile-name bg-proxy-verify-ec2-profile \
--role-name bg-proxy-verify-ec2-role
# Wait for IAM propagation
sleep 10
aws ec2 run-instances \
--image-id $AL2023_AMI_ID \
--instance-type t3.medium \
--security-group-ids '["$SG_ID"]' \
--subnet-id $SUBNET_ID \
--iam-instance-profile '{"Name":"bg-proxy-verify-ec2-profile"}'
# Install psql via SSM
dnf install -y postgresql16Test Table
PGPASSWORD=$PASSWORD psql \
-h $PROXY_ENDPOINT.ap-northeast-1.rds.amazonaws.com \
-p 5432 -U postgres -d postgres \
-c "CREATE TABLE IF NOT EXISTS switchover_test (
id SERIAL PRIMARY KEY,
ts TIMESTAMPTZ DEFAULT now(),
msg TEXT
);"Verification: RDS Proxy Switchover — Downtime Measurement
Measurement Script
Same approach as Part 1: execute queries at 1-second intervals, recording success/failure, latency, and server IP. Unlike Part 1 which used SELECT, this test uses INSERT ... RETURNING host(inet_server_addr()) to detect read-only errors during switchover.
measure.sh (full measurement script)
#!/bin/bash
ENDPOINT="$1"
PASSWORD="$2"
COUNT=${3:-200}
LOGFILE="/home/ec2-user/switchover_$(date +%Y%m%d_%H%M%S).csv"
echo "seq,timestamp,status,latency_ms,server_ip,message" > "$LOGFILE"
for i in $(seq 1 $COUNT); do
START_MS=$(date +%s%3N)
RESULT=$(PGPASSWORD="${PASSWORD}" psql -h "${ENDPOINT}" -p 5432 -U postgres -d postgres \
-t -A -c "INSERT INTO switchover_test (msg) VALUES ('seq=$i') RETURNING host(inet_server_addr());" 2>&1)
END_MS=$(date +%s%3N)
LATENCY=$((END_MS - START_MS))
TS=$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)
if echo "$RESULT" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "$i,$TS,OK,$LATENCY,$RESULT," >> "$LOGFILE"
else
MSG=$(echo "$RESULT" | tr '\n' ' ' | cut -c1-120)
echo "$i,$TS,FAIL,$LATENCY,,$MSG" >> "$LOGFILE"
fi
sleep 1
doneExecution
Started the measurement script in the background, confirmed writes were stable, then triggered the switchover.
nohup ./measure.sh $PROXY_ENDPOINT.ap-northeast-1.rds.amazonaws.com $PASSWORD 200 &After ~30 seconds of stable writes, executed the switchover.
aws rds switchover-blue-green-deployment \
--blue-green-deployment-identifier bgd-wmrsads60kvsah4c \
--switchover-timeout 300Results
Out of 200 writes, only 1 connection failure occurred.
seq,timestamp,status,latency_ms,server_ip,message
...
57,2026-04-10T01:59:58.077Z,OK,65,172.31.19.95,
58,2026-04-10T02:00:11.432Z,FAIL,12349,,SSL connection has been closed unexpectedly connection to server was lost
59,2026-04-10T02:00:12.553Z,OK,113,172.31.28.214,
60,2026-04-10T02:00:13.646Z,OK,87,172.31.28.214,
...| Metric | Value |
|---|---|
| Connection failures | 1 |
| Write unavailability | ~14 seconds (01:59:58 → 02:00:12) |
| Failure latency | 12,349ms (~12s) |
| Error message | SSL connection has been closed unexpectedly |
| IP switch | 172.31.19.95 (Blue) → 172.31.28.214 (Green) |
Analysis
-
Only 1 failure — Part 1's direct connection had 6 failures (all timeouts). RDS Proxy had just one. Per the documentation, the proxy detects the switchover and automatically redirects to the Green environment, which likely explains the reduced failure count.
-
Different error pattern — Direct connection produced timeouts (server unresponsive). RDS Proxy produced
SSL connection has been closed unexpectedly. The documentation states that "existing connections to the proxy are dropped" when the Green environment is promoted, so this SSL disconnect is likely the proxy dropping the connection. Note that the docs also mentionAdminShutdown: terminating connection due to administrator commandas an Aurora PostgreSQL error during switchover — this occurs after Blue enters read-only mode. The fact that we observed an SSL disconnect rather than AdminShutdown suggests the proxy maintained the client connection during Blue's read-only transition and dropped it upon detecting switchover completion. -
~14 seconds of write unavailability — Down from 26 seconds with direct connection (~46% reduction). Of those 14 seconds, ~12 seconds was the latency of seq 58. That query connected to Blue through the proxy, then received the SSL disconnect during the switchover process. Per the documentation, the proxy continues routing to Blue during the transitional period and drops connections upon detecting the switchover. The next query (seq 59) connected to Green immediately, showing the proxy's redirect is fast once the drop occurs.
-
No DNS propagation delay — In Part 1, DNS TTL of 60 seconds was the bottleneck. With RDS Proxy, the application always connects to the proxy endpoint, so there's no DNS switchover to wait for. The proxy handles routing internally.
-
Proxy API timing — Per the docs, Proxy APIs like
describe-db-proxy-targetsreflect updated targets only after switchover is fully complete, even though traffic routing switches earlier.
Summary
Cross-Series Comparison
| Metric | Direct (Part 1) | JDBC BG Plugin (Part 2) | RDS Proxy (this article) |
|---|---|---|---|
| Measurement method | psql, 1s interval | Java app, 1s interval | psql, 1s interval |
| Engine | Aurora PostgreSQL 16.9 → 17.6 | Aurora PostgreSQL 16.9 → 17.6 | Aurora PostgreSQL 16.9 → 17.6 |
| Connection failures | 6 | 0 | 1 |
| Downtime | ~26s | 0s (36s pause) | ~14s |
| Failure pattern | Timeout (3s × 6) | None | SSL disconnect (12s × 1) |
| Language constraint | None | Java only | None |
| DNS dependency | Yes (TTL 60s) | No (IP-based) | No (proxy detects) |
| Setup complexity | None | Medium (deps + config) | Medium (Proxy + IAM + Secrets Manager) |
| Additional cost | None | None | RDS Proxy pricing |
| Reconnection required | Yes | No (plugin handles it) | Yes (proxy drops connections) |
Key Takeaways
-
RDS Proxy cut downtime from 26s to 14s — A ~46% reduction compared to direct connection. In Part 1, DNS TTL of 60 seconds was the primary cause of downtime. Since RDS Proxy is unaffected by DNS propagation, this likely accounts for the improvement. However, the proxy continues routing to Blue during the switchover process and drops connections only after detecting completion, which took ~12 seconds in our test. This means it can't match the JDBC BG plugin's zero failures.
-
Single failure, easily handled with retry — Down from 6 failures with direct connection. A single retry in the application layer can further reduce effective downtime. The error message (
SSL connection has been closed unexpectedly) is detectable by connection pool health checks. -
Choose based on language and cost tolerance — Java apps needing minimal downtime: JDBC BG plugin (0 failures, but 36s query pause). Language-agnostic DNS delay elimination: RDS Proxy (additional cost). Already using RDS Proxy: no extra setup needed (but register the proxy target before creating the Blue/Green Deployment). Minimizing cost: direct connection + app-level retry (accept 26s downtime).
-
RDS Proxy's biggest advantage is ease of adoption — The JDBC BG plugin requires driver changes. If your application already connects through RDS Proxy, you get the benefit simply by using Blue/Green Deployments. For new Proxy setups, the only application change is the connection endpoint.
Cleanup
Resource deletion commands
# Delete Blue/Green Deployment
aws rds delete-blue-green-deployment \
--blue-green-deployment-identifier bgd-wmrsads60kvsah4c \
--delete-target \
--region ap-northeast-1
# Delete old Blue environment (renamed to -old1 after switchover)
aws rds delete-db-instance \
--db-instance-identifier bg-proxy-verify-w1-old1 \
--skip-final-snapshot
aws rds delete-db-cluster \
--db-cluster-identifier bg-proxy-verify-old1 \
--skip-final-snapshot
# Delete RDS Proxy
aws rds deregister-db-proxy-targets \
--db-proxy-name bg-proxy-verify \
--db-cluster-identifiers '["bg-proxy-verify"]'
aws rds delete-db-proxy --db-proxy-name bg-proxy-verify
# Delete Aurora cluster
aws rds delete-db-instance \
--db-instance-identifier bg-proxy-verify-w1 \
--skip-final-snapshot
aws rds delete-db-cluster \
--db-cluster-identifier bg-proxy-verify \
--skip-final-snapshot
# Delete EC2 instance
aws ec2 terminate-instances --instance-ids i-0478189b7d8e3aea9
# Delete IAM roles and policies
aws iam delete-role-policy --role-name bg-proxy-verify-role --policy-name SecretsManagerAccess
aws iam delete-role --role-name bg-proxy-verify-role
aws iam remove-role-from-instance-profile \
--instance-profile-name bg-proxy-verify-ec2-profile \
--role-name bg-proxy-verify-ec2-role
aws iam detach-role-policy \
--role-name bg-proxy-verify-ec2-role \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
aws iam delete-role --role-name bg-proxy-verify-ec2-role
aws iam delete-instance-profile --instance-profile-name bg-proxy-verify-ec2-profile
# Delete Secrets Manager secret
aws secretsmanager delete-secret \
--secret-id bg-proxy-verify-secret \
--force-delete-without-recovery
# Delete parameter groups
aws rds delete-db-cluster-parameter-group --db-cluster-parameter-group-name bg-proxy-verify-cpg
aws rds delete-db-cluster-parameter-group --db-cluster-parameter-group-name bg-proxy-verify-cpg-17
# Delete subnet group
aws rds delete-db-subnet-group --db-subnet-group-name bg-proxy-verify-subnet
# Delete security group
aws ec2 delete-security-group --group-id $SG_ID