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.
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"
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 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
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.
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"
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 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
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'
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.
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
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.
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.
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
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
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.
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.
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.
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.
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.
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.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy