Guide · AWS Aurora · Multi-Region Database

Aurora Global Database for MCP Servers — Multi-Region Replication, Sub-Second RPO, Managed Failover

Aurora Global Database extends a single Aurora cluster across up to five AWS regions with storage-level replication that typically delivers less than one second of lag — MCP monitoring platforms and agent platforms that need their probe database accessible in multiple regions for read locality or disaster recovery use Global Database instead of application-level cross-region replication. Three subtleties determine whether a global database deployment works as expected in a failover: managed planned failover and detach-and-promote are two different operations with very different data-loss profiles — managed planned failover stops writes on the primary, drains replication lag to zero, then promotes the target secondary, guaranteeing no data loss; detach-and-promote promotes a secondary immediately without waiting for lag to drain and is used only when the primary is unreachable, accepting up to ~1 second of data loss; write forwarding from secondary to primary adds 20–50 ms per write compared to connecting directly to the primary, making it unsuitable for write-intensive probe workers — use it only for occasional administrative writes from secondary-region tooling; and the AuroraGlobalDBReplicationLag metric measures lag per secondary region in milliseconds, and an alarm on this metric is the primary signal that the network path between regions is degraded before it affects application reads.

TL;DR

Create an Aurora Global Database with a primary cluster in your write region and secondary clusters in read-locality or DR regions. Each cluster gets its own endpoint — write to the primary cluster writer endpoint, read from the nearest cluster's reader endpoint. For planned maintenance failover, use failover-global-cluster API (zero data loss, ~30–60 seconds downtime). For DR failover when the primary is down, use remove-from-global-cluster to promote the secondary (up to ~1 second data loss). After any failover, update application connection strings.

Global Database architecture

Aurora Global Database uses dedicated replication infrastructure at the storage layer — separate from the binlog-based replication Aurora uses for read replicas within a region. Storage-level replication bypasses the database engine and runs in parallel, which is why typical lag is under one second even between distant regions (us-east-1 to ap-southeast-1 averages 200–400 ms).

ComponentDescription
Primary clusterAccepts writes; one writer instance + optional readers within the same region. Standard Aurora cluster; no special configuration required.
Secondary cluster(s)Read-only replica of the primary at the storage level. Up to 5 secondary regions. Each secondary has its own reader endpoint for low-latency local reads.
Global write forwardingOptional feature that lets applications send writes to a secondary cluster; the secondary forwards them to the primary region. Adds ~20–50 ms roundtrip latency to the write path.
Replication lagMeasured by AuroraGlobalDBReplicationLag (ms per secondary); typically <1,000 ms; p99 during heavy write load may reach 2,000 ms.
RPO<1 second for unplanned failover (detach-and-promote); 0 for managed planned failover.
RTO<1 minute for managed planned failover; varies (application-dependent DNS propagation) for detach-and-promote.

Creating a Global Database with AWS CLI

# Step 1: Create or identify the primary Aurora cluster (standard creation)
aws rds create-db-cluster \
  --db-cluster-identifier mcp-probe-primary \
  --engine aurora-postgresql \
  --engine-version "16.2" \
  --master-username admin \
  --master-user-password "REPLACE_WITH_SECRETS_MANAGER_VALUE" \
  --db-subnet-group-name mcp-db-subnets-us-east-1 \
  --region us-east-1

# Step 2: Create the global database wrapping the primary cluster
aws rds create-global-cluster \
  --global-cluster-identifier mcp-probe-global \
  --source-db-cluster-identifier arn:aws:rds:us-east-1:123456789012:cluster:mcp-probe-primary

# Step 3: Add a secondary cluster in EU West 1
aws rds create-db-cluster \
  --db-cluster-identifier mcp-probe-secondary-eu \
  --global-cluster-identifier mcp-probe-global \
  --engine aurora-postgresql \
  --engine-version "16.2" \
  --db-subnet-group-name mcp-db-subnets-eu-west-1 \
  --enable-global-write-forwarding \
  --region eu-west-1

# Each secondary needs at least one DB instance
aws rds create-db-instance \
  --db-instance-identifier mcp-probe-secondary-eu-reader \
  --db-cluster-identifier mcp-probe-secondary-eu \
  --db-instance-class db.r7g.large \
  --engine aurora-postgresql \
  --region eu-west-1

The primary and each secondary maintain independent endpoints. Write all probe data through the primary cluster's writer endpoint; configure read-heavy reporting queries in the EU region to use the secondary cluster's reader endpoint for lower latency to European users.

CDK setup

import * as rds from "aws-cdk-lib/aws-rds";

// Primary cluster (standard Aurora cluster)
const primaryCluster = new rds.DatabaseCluster(this, "PrimaryCluster", {
  engine: rds.DatabaseClusterEngine.auroraPostgres({
    version: rds.AuroraPostgresEngineVersion.VER_16_2,
  }),
  vpc: primaryVpc,
  writer: rds.ClusterInstance.serverlessV2("writer"),
  serverlessV2MinCapacity: 2,
  serverlessV2MaxCapacity: 32,
  iamAuthentication: true,
});

// Global Database container (wraps the primary)
const globalDb = new rds.GlobalCluster(this, "GlobalDb", {
  globalClusterIdentifier: "mcp-probe-global",
  sourceDbClusterIdentifier: primaryCluster.clusterArn,
  engine: rds.DatabaseClusterEngine.auroraPostgres({
    version: rds.AuroraPostgresEngineVersion.VER_16_2,
  }),
  deletionProtection: true,
});

// Secondary cluster in eu-west-1 (deployed in a separate CDK stack/region)
// In the secondary-region stack:
const secondaryCluster = new rds.DatabaseCluster(this, "SecondaryCluster", {
  engine: rds.DatabaseClusterEngine.auroraPostgres({
    version: rds.AuroraPostgresEngineVersion.VER_16_2,
  }),
  vpc: secondaryVpc,
  writer: rds.ClusterInstance.serverlessV2("writer"),
  serverlessV2MinCapacity: 0.5,   // lower minimum for secondary — only handles reads
  serverlessV2MaxCapacity: 16,
  globalCluster: globalDb,         // associates with the global database
});

Failover procedures

Two failover paths exist with different data-loss guarantees:

Managed planned failover (zero data loss)

Use when the primary region is healthy and you are doing scheduled maintenance or a planned region migration:

# Initiate managed planned failover — primary stops accepting writes,
# lag drains to zero, secondary is promoted; the old primary rejoins as secondary
aws rds failover-global-cluster \
  --global-cluster-identifier mcp-probe-global \
  --target-db-cluster-identifier arn:aws:rds:eu-west-1:123456789012:cluster:mcp-probe-secondary-eu \
  --allow-data-loss false

# Monitor the failover status
aws rds describe-global-clusters \
  --global-cluster-identifier mcp-probe-global \
  --query "GlobalClusters[0].GlobalClusterMembers[*].{ARN:DBClusterArn,IsWriter:IsWriter,Status:Status}"

Detach-and-promote (disaster recovery)

Use only when the primary region is unreachable and you need to restore write capability in the secondary region:

# Detach the secondary from the global database — it becomes a standalone cluster
# Any replication lag at this moment represents potential data loss (~0 to 1 second)
aws rds remove-from-global-cluster \
  --global-cluster-identifier mcp-probe-global \
  --db-cluster-identifier arn:aws:rds:eu-west-1:123456789012:cluster:mcp-probe-secondary-eu \
  --region eu-west-1

# The secondary is now a standalone Aurora cluster with write capability
# Update application connection strings to the eu-west-1 writer endpoint

# After the primary region recovers, re-add it as a new secondary
aws rds create-db-cluster \
  --db-cluster-identifier mcp-probe-new-secondary-us \
  --global-cluster-identifier mcp-probe-global \
  --engine aurora-postgresql \
  --engine-version "16.2" \
  --db-subnet-group-name mcp-db-subnets-us-east-1 \
  --region us-east-1

After any failover: update your application's write endpoint to the new primary cluster's writer endpoint. If using RDS Proxy, update the proxy's target cluster. Consider Route 53 CNAME records with a short TTL (30s) pointing to the current writer endpoint to make this switchover application-transparent.

Write forwarding

Global write forwarding lets an application connected to a secondary cluster issue writes that are automatically forwarded to the primary region. This is useful for occasional administrative writes from secondary-region tooling without requiring a separate primary-region connection:

-- Enable write forwarding on a secondary cluster
aws rds modify-db-cluster \
  --db-cluster-identifier mcp-probe-secondary-eu \
  --enable-global-write-forwarding \
  --region eu-west-1

-- In a PostgreSQL session against the secondary endpoint:
SET aurora_replica_read_consistency = "session";
-- Normal read: returns from local secondary (low latency)
SELECT count(*) FROM probe_results WHERE checked_at > NOW() - INTERVAL '5 minutes';

-- Forwarded write (goes to primary; adds cross-region roundtrip latency ~20-50ms):
INSERT INTO alert_events (server_slug, event_type) VALUES ('my-mcp-server', 'manual_trigger');

Write forwarding limitation: forwarded writes are NOT suitable for high-throughput probe result inserts. Each forwarded write incurs an additional network roundtrip to the primary region. Use write forwarding only for low-volume administrative operations; direct probe workers to the primary cluster's writer endpoint for all high-frequency writes.

Replication lag monitoring

# CloudWatch alarm: cross-region lag exceeds 5 seconds for 3 consecutive minutes
aws cloudwatch put-metric-alarm \
  --alarm-name "mcp-global-db-lag-eu" \
  --namespace "AWS/RDS" \
  --metric-name "AuroraGlobalDBReplicationLag" \
  --dimensions Name=DBClusterIdentifier,Value=mcp-probe-secondary-eu \
  --statistic Maximum \
  --period 60 \
  --evaluation-periods 3 \
  --threshold 5000 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --alarm-actions arn:aws:sns:eu-west-1:123456789012:mcp-ops-alerts

# Additional metric: AuroraGlobalDBDataTransferBytes — bytes replicated to this secondary per second
# Spike indicates a bulk write on the primary; lag spike following = normal

AliveMCP multi-region probe pattern

AliveMCP deploys probe workers in us-east-1, eu-west-1, and ap-southeast-1 to detect region-specific MCP endpoint failures (a server may be reachable from US but not from EU due to a regional CDN outage). Each probe worker writes results to the primary cluster's writer endpoint in us-east-1. The secondary clusters in eu-west-1 and ap-southeast-1 serve the public status dashboard — read-only queries for 7-day uptime history run against the local secondary, eliminating the US→EU latency that would otherwise affect p95 dashboard load time. The AuroraGlobalDBReplicationLag alarm is set to 5 seconds; if lag exceeds this, the dashboard switches to displaying cached data from a 60-second CloudFront cache to prevent stale-read anomalies from appearing to users as real outages.

Common failure modes

SymptomCauseFix
Managed failover stuck in "failing-over" state for more than 5 minutesPrimary cluster has uncommitted long-running transactions; lag cannot drain to zero while they are openTerminate long-running transactions on the primary before initiating failover; set a statement_timeout for background workers
Secondary cluster endpoints return stale data after a heavy primary write burstReplication lag is elevated above normal; reads from secondary return data behind the primary by up to a few secondsFor reads that must reflect the latest writes, use the primary cluster's reader endpoint; use secondary endpoints only for non-latency-sensitive analytics
"GlobalClusterAlreadyExistsFault" when adding a second secondaryAttempting to create a global cluster wrapper when one already existsUse add-regional-cluster to attach a new secondary cluster to an existing global database
Write forwarding returns "ERROR: cannot execute insert in a read-only transaction"Write forwarding was not enabled on the secondary cluster or the feature flag is not set in the sessionEnable write forwarding on the cluster via modify-db-cluster --enable-global-write-forwarding; verify with SHOW aurora_read_replica_read_consistency
Post-failover application still writes to the old primary (now secondary)Application connection strings were not updated after failover; old primary is now a read-only secondary and rejects writesUse a Route 53 CNAME with a short TTL (30s) for the writer endpoint; update the CNAME record during failover to point to the new primary's endpoint
Cost unexpectedly doubled after adding a secondary regionEach secondary region incurs full Aurora instance costs plus data transfer costs for replicationSize the secondary instances appropriately for read-only workloads (often smaller than the writer); use Serverless v2 on secondary with lower minCapacity