Cloud-Native Database Selection

Choose the right cloud database for your workload. Covers relational, NoSQL, time-series, graph, and vector databases across AWS, Azure, and GCP with performance, cost, and migration considerations.

This reference describes how to choose database systems for applications that run in cloud environments, focusing on the technical decision points that determine whether a database will function correctly when deployed on a platform like Kubernetes or in a containerized environment. This matters when you are deploying stateful services that must survive pod restarts, scale horizontally, or integrate with cloud-native infrastructure patterns such as service discovery, health checks, and automated failover.

Choose Based on Data Access Patterns

Select for Read-Heavy Workloads

For applications where reads significantly outnumber writes, select a database with built-in read replicas or read-only nodes.

Use the following SQL command to check if a database supports read replicas:

SHOW VARIABLES LIKE 'rds.read_replica';

If the result shows rds.read_replica as ON, the system supports read replicas.

In PostgreSQL, enable read replicas with:

SELECT pg_create_physical_replica('replica1', 'primary_host:5432');

When using Kubernetes, ensure your deployment specifies readinessProbe and livenessProbe that can distinguish between read-only and read-write operations:

livenessProbe:
  exec:
    command:
      - pg_isready
      - -h
      - localhost
      - -p
      - "5432"

Select for Write-Heavy Workloads

For applications with frequent writes, choose databases that support horizontal scaling through sharding or partitioning.

In MySQL, enable horizontal scaling via partitioning:

ALTER TABLE orders ADD PARTITION (PARTITION p2024 VALUES LESS THAN (2025));

The failure mode occurs when queries target a specific partition without proper routing, resulting in:

ERROR 1526 (HY000): Table has no partition for value

In PostgreSQL, use table inheritance to implement sharding:

CREATE TABLE orders_2024 PARTITION OF orders FOR VALUES FROM (2024) TO (2025);

Choose Based on Storage and Compute Separation

Select for Separated Storage

Choose databases that decouple storage from compute to allow independent scaling.

In Kubernetes, deploy a database with persistent volume claims:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi

Ensure that the database pod references this claim:

volumeMounts:
  - name: db-storage
    mountPath: /var/lib/postgresql/data
volumes:
  - name: db-storage
    persistentVolumeClaim:
      claimName: db-pvc

Select for Stateful Sets

For databases that require stable network identities, use StatefulSets instead of Deployments.

In Kubernetes, define a StatefulSet with:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql
spec:
  serviceName: "postgresql"
  replicas: 3
  selector:
    matchLabels:
      app: postgresql

The key difference from Deployments is that StatefulSets maintain stable DNS names and persistent identities across pod restarts.

Choose Based on Connection Management

Select for High Concurrency

For applications with many concurrent connections, choose databases that support connection pooling or have built-in connection limits.

In PostgreSQL, configure max_connections:

ALTER SYSTEM SET max_connections = 1000;
SELECT pg_reload_conf();

When deploying to Kubernetes, set resource limits to prevent overloading:

resources:
  limits:
    memory: "2Gi"
    cpu: "1"
  requests:
    memory: "1Gi"
    cpu: "500m"

Select for Connection Limits

When a database has strict connection limits, use connection pooling with pgbouncer:

[databases]
mydb = host=primary port=5432 dbname=mydb

[pgbouncer]
pool_mode = transaction
default_pool_size = 20
max_client_conn = 100

If you do not configure connection pooling and exceed limits, the database returns:

FATAL: sorry, too many clients already

Choose Based on Backup and Recovery

Select for Automated Backups

Choose databases that support automated backups without requiring manual intervention.

In PostgreSQL, enable WAL archiving:

ALTER SYSTEM SET archive_mode = on;
ALTER SYSTEM SET archive_command = 'cp %p /var/lib/postgresql/backup/%f';
SELECT pg_reload_conf();

The backup process uses the following command:

pg_basebackup -D /var/lib/postgresql/backup -R -v

Select for Point-in-Time Recovery

For systems requiring recovery to a specific point in time, select databases that support WAL-based recovery.

In PostgreSQL, restore from a base backup and replay WAL files:

pg_waldump /var/lib/postgresql/backup/wal/000000010000000000000001 | grep -E 'BEGIN|COMMIT'

The recovery process requires a recovery configuration file:

recovery_target_time = '2024-05-15 10:00:00'
standby_mode = 'on'
primary_conninfo = 'host=primary port=5432 user=repl'

Choose Based on Disaster Recovery

Select for Multi-Zone Deployment

For high availability, choose databases that support multi-zone deployment patterns.

In Kubernetes, configure pod anti-affinity to spread replicas:

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: postgresql
          topologyKey: topology.kubernetes.io/zone

If you do not configure anti-affinity, pods may schedule to the same zone and fail during zone outages.

Select for Failover Automation

For systems requiring automatic failover, choose databases that support leader election or replication monitoring.

In PostgreSQL, configure streaming replication with:

SELECT pg_start_replication('standby1', 0, 'primary_slot');

Monitor replication lag using:

SELECT 
  client_addr,
  state,
  sync_state,
  write_lag,
  flush_lag,
  replay_lag
FROM pg_stat_replication;

If a replica falls behind by more than 10 seconds, the system may begin reporting:

WARNING: replica is falling behind

Choose Based on Data Consistency

Select for Strong Consistency

For systems requiring ACID compliance, select databases that support strong consistency models.

In PostgreSQL, use transactions with SERIALIZABLE isolation level:

BEGIN ISOLATION LEVEL SERIALIZABLE;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

If you do not specify an isolation level, the default READ COMMITTED may lead to phantom reads.

Select for Eventual Consistency

For systems tolerating eventual consistency, choose databases that support read-replica lag or conflict resolution.

In MongoDB, enable replica sets:

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "primary:27017" },
    { _id: 1, host: "secondary:27017" }
  ]
});

If you do not configure replica sets, writes may be lost during primary failure.

Choose Based on Data Migration

Select for Zero-Downtime Migration

For systems requiring zero-downtime migration, choose databases with built-in migration tools or streaming replication.

In PostgreSQL, use pg_dump and pg_restore:

pg_dump -h oldhost -U user -d database > backup.sql
pg_restore -h newhost -U user -d database backup.sql

The process fails if the target database is not in single-user mode:

ERROR:  database "mydb" is being accessed by other users

Select for Incremental Migration

For systems requiring incremental migration, choose databases that support logical replication or change data capture.

In PostgreSQL, enable logical replication:

CREATE PUBLICATION mypub FOR TABLE users;

Then subscribe from another database:

CREATE SUBSCRIPTION mysub CONNECTION 'host=primary port=5432 dbname=mydb' PUBLICATION mypub;

If the subscription fails due to missing publication, the error is:

ERROR:  publication "mypub" does not exist

Sharp Edges and Failure Modes

Silent Failures in Resource Limits

Databases that do not enforce resource limits silently fail when exceeding memory or CPU thresholds. In PostgreSQL, a large query may cause:

FATAL: out of memory

Even if the system has sufficient total resources, individual queries can trigger OOM conditions.

Confusion Between Read Replicas and Standby Nodes

Read replicas and standby nodes are often confused. A read replica allows reads but not writes, while a standby node is a replica used for failover.

In PostgreSQL, check if a node is a standby:

SELECT pg_is_in_recovery();

If this returns true, the node is in recovery mode, which may be different from being a read-only replica.

Incorrect Use of Connection Pooling

Using connection pooling without proper configuration causes connection exhaustion. The error:

FATAL: sorry, too many clients already

appears when the pool size exceeds the database's max_connections setting.

Misunderstanding Backup and Restore Processes

Backup tools that do not support incremental backup may require full backups for every change, leading to resource waste and longer restore times. The command:

pg_basebackup -D /var/lib/postgresql/backup -R -v

fails if the target directory already exists without the proper permissions.

Ignoring Network Topology

Deploying databases without considering network topology causes performance degradation or availability issues. In Kubernetes, using NodePort instead of LoadBalancer for external access may cause connection timeouts when pods are moved between nodes.

Misconfigured Readiness Probes

A readiness probe that checks only the database's listening port without validating actual data access may mark a node as ready while it is actually unreachable:

readinessProbe:
  exec:
    command:
      - pg_isready
      - -h
      - localhost
      - -p
      - "5432"

This probe passes even when the database is in recovery mode and cannot serve queries.

This page was rewritten on 16 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.