---
title: "Time-Series Database HA and Disaster Recovery"
description: "How to design high availability and disaster recovery for time-series Postgres: RPO/RTO targets, failover options, and hypertable-specific mechanics"
section: "Postgres best practices"
published: 2026-09-25T12:23:41.388Z
updated: 2026-09-25T00:00:00.000Z
---

*Updated at Sep 25, 2026*

> **TimescaleDB is now Tiger Data.**

High availability and disaster recovery get talked about as one topic, but they solve two different problems. A time-series Postgres workload that's ingesting sensor data, financial ticks, or infrastructure metrics around the clock needs both, and it needs them designed around how hypertables, compression, and continuous aggregates actually behave under failure, not just generic Postgres advice. This guide explains high availability (HA) vs. disaster recovery (DR) for time-series database design. You will learn how to define recovery point objective (RPO) and recovery time objective (RTO) targets for high-ingest workloads, compare database failover options, and understand mechanics specific to time-series Postgres; including how failover impacts compressed hypertables, WAL replication, chunk boundaries, and continuous aggregate refreshes.

## What is the difference between high availability and disaster recovery?

High availability (HA) is a proactive process; a way of ensuring that the system at large keeps running through a small point of failure with minimal downtime. Disaster recovery (DR) is a reactive process, and covers how the system can be restored after a more serious loss, like a region outage, a bad deployment, or data corruption, even if that takes longer and involves some data loss along the way.

HA and DR address different points of failure, and they use different mechanisms to keep your data safe. HA relies on automatic failover to a live standby that's already caught up. DR relies on restoring from a backup or a recovery fork after the primary and its standbys are gone, or after the data itself has been damaged.

This is where a common assumption breaks down: replication is a mechanism, not a safeguard in itself. Having a replica doesn't automatically mean you have high availability. You also need automatic failure detection, promotion of the replica to primary, and redirection of client connections. Without those three pieces, a replica is just a copy that a human has to manually turn into a primary.

Backups and point-in-time recovery (PITR) are a component of a DR plan, but not the entire DR plan itself. The difference comes down to the kind of event you're handling: a replica going down and being replaced automatically is an HA event, while a bad migration that deletes data, or an entire region going offline, is a DR event that replication alone can't solve. In fact, a healthy replica would have faithfully replicated that bad migration right along with everything else. 

## RPO and RTO for time-series workloads

Recovery Point Objective (RPO) is the maximum amount of data loss, measured in time, that your organization is willing to accept after a failure. It's less about what the system can tolerate and more about what you're comfortable losing: is it acceptable to lose the last hour of data, the last week, the last month, or (in the worst case) all of it? That's as much a security and liability question as a technical one, and the answer depends on what the data is worth and what you're accountable for. Recovery Time Objective (RTO) is the maximum acceptable duration of downtime before service must be restored. Both RPO and RTO are subjective measures that depend on the risk tolerance of your system and organization at large, so it's worth consulting other teams and any regulatory requirements to determine the proper targets for your organization. 

Expectations for both numbers have tightened across the industry. Sub-hour RTO and sub-five-minute RPO are increasingly treated as a baseline for mission-critical workloads, with near-zero RPO expected for the most latency-sensitive categories, like financial tick data or safety-critical telemetry. This is a reliability engineering baseline, not a regulatory requirement, and it's worth treating it that way when you set your own targets.

Instead of adopting a generic industry standard for RPO and RTO, base your targets on the actual cost of downtime to your business. It's best to work backward from what a specific failure actually costs your business: how much ingest you can afford to lose, how stale a customer-facing dashboard can get before it's a problem, or what SLA you'd break. A telemetry pipeline feeding a nightly report can tolerate a very different RPO than a system driving real-time alerting.

## Does Postgres have automatic failover built in?

No, not on its own. Postgres high availability isn't something vanilla PostgreSQL ships with: it provides manual failover primitives, like `pg_ctl` and trigger files, but no automatic failure detection, promotion, or client redirection out of the box. If a primary goes down, someone has to notice and manually promote a replica.

Patroni is the de facto standard tool the Postgres community uses to close that gap. Alternatives like [<u>pg_auto_failover</u>](https://github.com/hapostgres/pg_auto_failover) and [<u>repmgr</u>](https://github.com/enterpriseDB/repmgr) exist too, each with a different architecture for coordinating promotion.

Practitioners describe Patroni as solid in production once it's configured, but rough around the edges to set up initially. Getting it working means standing up and tuning a distributed configuration store like etcd or Consul, a real chunk of operational work before it just works. That's a fair trade-off to weigh, not a reason to skip automatic failover and run everything by hand.

## Failover options compared

The mechanism you choose determines how fast failover happens, how much data you can lose, and who's responsible for keeping it running.

Hosting your Postgres database elsewhere can bring additional benefits, such as providing additional safeguards in case an incident were to happen. 

| **Mechanism** | **Typical failover time** | **Data-loss risk** | **Operational complexity** | **Who manages it** |
| --- | --- | --- | --- | --- |
| Tiger Cloud HA replica (automatic) | Within 30 seconds | Near-zero with sync replication; small window with async | Low | Tiger Cloud, automatically |
| Self-hosted Postgres + Patroni (automatic) | Seconds to low tens of seconds | Depends on sync/async configuration | High (etcd/Consul setup and tuning) | You, self-managed |
| Self-hosted Postgres + `pg_auto_failover` (automatic) | Seconds to low tens of seconds | Depends on sync/async configuration | Moderate to high | You, self-managed |
| Self-hosted Postgres + manual `pg_ctl` failover | As long as it takes a human to notice and act | Depends on how current the replica is when promoted | Highest (no automatic detection) | You, self-managed |

Sync and async replication are worth separating out explicitly, since the row above depends on which one you pick. A synchronous replica confirms every write before the primary commits, so there's no lag between the two and the highest possible data integrity, at the cost of added write latency. An asynchronous replica commits without waiting for that confirmation, which keeps ingest latency lower but opens a small window where a failure could lose the writes that hadn't replicated yet. For more on how this plays out with more than one replica, see [<u>bulletproofing a Postgres database with multiple replicas</u>](https://www.tigerdata.com/blog/bulletproofing-your-database-with-multiple-postgresql-replicas).

## Which HA/DR pattern should you use? A decision framework

**Choose an HA replica with asynchronous replication if:** you can tolerate a small window of data loss but need fast, automatic recovery from an infrastructure failure like a node crash or an AZ outage.

**Choose an HA replica with synchronous replication if:** you need zero data loss on write and can accept the added write latency that comes from waiting for replica confirmation.

**Choose PITR, a recovery fork, if:** you need to recover from a bad deploy, a bad migration, or an accidental deletion. This is logical or human error, not a hardware failure, and failover doesn't help here. A healthy replica would have replicated the mistake right along with everything else.

**Choose self-hosted streaming replication with Patroni if:** you're running self-hosted TimescaleDB, need automatic failover without a managed platform, and have the operational capacity to run and tune Patroni and its configuration store.

**Choose manual failover only if:** your downtime tolerance is high enough that the operational investment in automatic tooling isn't worth it for the workload. For a production time-series system, this is rarely the right default.

## Time-series-specific HA/DR mechanics

Generic Postgres HA/DR guidance doesn't fully cover time-series workloads. Compression, chunking, and continuous aggregates introduce mechanics that a standard single-table Postgres replica setup doesn't have to think about, and getting them wrong is how a failover or restore looks fine on the surface while dashboards quietly show stale or incomplete data underneath.

### How compression interacts with replication

Compressing, decompressing, and recompressing chunks generates additional write-ahead log (WAL) activity that a replica has to stream and apply. That extra volume shows up most noticeably during backfills into already-compressed chunks, since writing into one means decompressing it, applying the write, and recompressing it, and all of that gets logged and shipped to every replica.

This doesn't change the correctness of failover. A promoted replica ends up in the same compressed or uncompressed state as the primary was, because it applied the exact same WAL. It just means that a compression-heavy workload with frequent backfills is a workload where you want to watch replication lag more closely, since that lag is your effective RPO if the primary fails before a replica catches up.

### Hypertable chunk replication

A [<u>hypertable</u>](https://www.tigerdata.com/docs/reference/timescaledb/hypertables) isn't one physical table under the hood. It's a parent table plus many child tables, called chunks, each holding a time slice of the data. That structure matters for query planning and compression, but it turns out not to matter much for standard physical, WAL-based streaming replication, which is the mechanism behind both [<u>Tiger Cloud's HA replicas</u>](https://www.tigerdata.com/blog/how-timescale-replication-works-enabling-postgres-ha) and self-hosted Patroni-managed failover.

Streaming replication operates below the hypertable abstraction. It ships block-level WAL changes, and chunk creation, compression conversions, and chunk-boundary decisions are all just more WAL records, the same as any other DDL or DML in Postgres. A replica applies that stream in order, so its set of chunks, their boundaries, and their compression state end up identical to the primary's at the moment of promotion. That's why failover doesn't require hypertable-aware replication tooling for the HA case: the replica was never behind on structure, only on time.

Where hypertable structure does matter is in replication mechanisms that don't ship raw WAL, like logical replication tools that copy row-level changes instead. Those tools have to handle compressed chunks explicitly, since compression changes how rows are physically represented on disk. That's a different mechanism from the primary-to-HA-replica physical replication this guide focuses on, but worth knowing if you're evaluating a logical-replication-based migration or sync tool alongside your HA setup.

### Continuous aggregates during failover and restore

A [<u>continuous aggregate</u>](https://www.tigerdata.com/docs/learn/continuous-aggregates) is a materialized view that refreshes on a schedule, catching up on whatever raw data changed since the last refresh. When a replica is promoted during failover, its continuous aggregates are already in whatever state they were in when the WAL stream caught up to the point of failure, because the materialized data lives in ordinary hypertables that replicate the same way the raw data does. There's no separate recovery step required for the aggregate itself.

What survives failover intact is correctness, and that's the guarantee that actually matters. A promoted replica never serves wrong aggregate results, only, at worst, slightly stale ones — and that ordering is the whole point. A fast failover that returned incorrect rollups would be worse than a slow one, because speed counts for nothing if the answers can't be trusted. Freshness is the lesser, recoverable issue: if a refresh was scheduled but hadn't run yet at the moment of failure, the aggregate is current up to its last completed refresh, not up to the second. The next scheduled refresh, or a manual `refresh_continuous_aggregate` call, catches it up to the new primary's current state. If your workload needs dashboards that are current to the second even in that gap, a [<u>real-time aggregate</u>](https://www.tigerdata.com/docs/learn/continuous-aggregates/real-time-aggregates) combines the materialized rollup with the newest raw data in a single query, so the answer stays current without waiting on the refresh schedule.

After a restore from a PITR fork, the same logic applies: the continuous aggregate comes back in whatever state it was in at the recovery point, and refresh policies resume on schedule from there.

### Retention policies during recovery

A PITR fork is a copy of the service as it existed at a specific point in time, before anything that happened after that point, including retention-policy drops. That means if a retention policy deleted a chunk after your chosen recovery point, that chunk's data is still present in the fork. This is often exactly why someone creates a fork in the first place, to recover data before an unwanted deletion caught up to it.

That data doesn't stay protected indefinitely just because it survived in the fork. If the same retention policy is still configured with its original interval, it eventually drops that data again once the chunk crosses the same age threshold on the fork's own timeline. Recovering data through a fork buys you a window to extract or re-import it, not a permanent override of the retention policy. If you want to keep the older data around, adjust or disable the policy on the fork itself.

In-flight jobs, whether that's a continuous aggregate refresh, a compression job, or a retention drop that was actively running at the moment of failover, don't leave the database in a half-finished state. These run as ordinary Postgres background jobs inside their own transactions, so they either commit fully or roll back entirely. An interrupted job simply doesn't complete and gets picked up again on its next scheduled run after failover or restore.

## Self-hosted HA/DR patterns for Postgres

Teams running self-hosted TimescaleDB build HA/DR out of three pieces: native Postgres streaming replication (sync or async) as the replication mechanism, [<u>Patroni</u>](https://www.tigerdata.com/docs/deploy/self-hosted/replication-and-ha/about-ha) as the automatic-failover layer on top of it, and pgBackRest as the backup and PITR tool.

As covered above, Postgres's own replication doesn't include automatic failover. That's exactly the gap Patroni fills, coordinating leader election and promotion through a distributed configuration store so a failure gets detected and resolved without a human in the loop.

A self-hosted stack typically needs:

- A primary and one or more replicas, using [<u>streaming replication configured as sync or async</u>](https://www.tigerdata.com/docs/deploy/self-hosted/replication-and-ha/configure-replication)
- Patroni plus a distributed configuration store, like etcd or Consul, to coordinate failure detection and promotion
- pgBackRest, or a comparable backup tool, for [<u>physical and logical backups</u>](https://www.tigerdata.com/docs/deploy/self-hosted/backup-and-restore/logical-backup) and PITR

The upside is full control: no vendor lock-in, and it works with any Postgres or TimescaleDB deployment, including on-prem and Kubernetes. For the Kubernetes-specific version of this, see [<u>how backup and restore work for Postgres on Kubernetes</u>](https://www.tigerdata.com/blog/how-i-learned-to-love-postgresql-on-kubernetes-backup-restore-on-timescale).

The honest downside is the operational overhead. Running and tuning Patroni and its configuration store is real, ongoing work, on top of monitoring replication lag, testing failover regularly, and keeping backup tooling current. For a deeper look at the replication mechanics underneath all of this, see [<u>Postgres replication best practices</u>](https://www.tigerdata.com/learn/best-practices-for-postgres-database-replication) and [<u>a full guide to Postgres replication</u>](https://www.tigerdata.com/learn/postgresql-database-replication-guide). For the backup and DR side specifically, see [<u>Postgres backup and disaster recovery questions, answered</u>](https://www.tigerdata.com/blog/database-backups-and-disaster-recovery-in-postgresql-your-questions-answered), and for background on how backups can be made significantly faster with the right tooling, [<u>how we made Postgres backups 100x faster with pgBackRest</u>](https://www.tigerdata.com/blog/making-postgresql-backups-100x-faster-via-ebs-snapshots-and-pgbackrest).

## Managed HA/DR with Tiger Cloud

Tiger Cloud services have [<u>rapid recovery enabled by default</u>](https://www.tigerdata.com/blog/how-high-availability-works-in-our-cloud-database), so a compute failure gets new infrastructure provisioned and WAL replayed automatically in about thirty seconds. For workloads with less tolerance for downtime, [<u>HA replicas</u>](https://www.tigerdata.com/docs/deploy/tiger-cloud/tiger-cloud-aws/high-availability/high-availability) are available as an upgrade on top of that.

HA replicas are exact, up-to-date copies of your database hosted across multiple availability zones within the same region as the primary. When the primary fails, Tiger Cloud automatically fails over to an HA replica within 30 seconds. Replication can be configured as synchronous or asynchronous, with the same integrity-versus-ingest-latency trade-off covered earlier in this guide. For more on how this replication mechanism works under the hood, see [<u>how Tiger Cloud's replication works to enable Postgres HA</u>](https://www.tigerdata.com/blog/how-timescale-replication-works-enabling-postgres-ha).

PITR on Tiger Cloud is delivered through recovery forks. A fork is a copy of the service as it existed at a chosen point in the past. You point your application at the fork once it's ready, and the original service can be paused during that process so you're not paying for compute on both the fork and the original at the same time. See [<u>creating a PITR recovery fork</u>](https://www.tigerdata.com/docs/deploy/tiger-cloud/tiger-cloud-aws/high-availability/backup-restore) for the specifics.

It's worth being precise about a common point of confusion: HA replicas and read replicas are not the same feature. HA replicas exist to take over automatically if the primary fails. [<u>Read replicas</u>](https://www.tigerdata.com/blog/scalable-postgresql-high-availability-read-scalability-streaming-replication-fb95023e2af) exist to horizontally scale read traffic. A read replica is not automatically a failover target, and treating it as one is a good way to discover that gap during an actual outage rather than before one.

Tiered, object-storage data has its own retention behavior that's relevant to recovery. Per the [<u>tiered data documentation</u>](https://www.tigerdata.com/docs/build/data-management/storage/tiered-data-replicas-forks), deleted tiered chunks are retained for 14 days before permanent deletion, specifically to keep PITR and restore possible within that window.

None of this makes self-hosted the wrong choice. The same replication concepts apply, just without you having to run and tune the coordination layer yourself.

## Migrating from self-hosted HA/DR to a managed path

The common path into Tiger Cloud's managed HA/DR starts with teams already running self-hosted TimescaleDB with Patroni-managed failover and pgBackRest-based backups, who want to hand off the operational burden while keeping the same reliability guarantees, or improving on them.

What changes and what doesn't is easy to pin down. The underlying replication concepts, sync versus async, WAL streaming, stay exactly the same. What goes away is running and tuning Patroni and its configuration store yourself, and maintaining your own backup and PITR tooling.

This transition is also a reasonable moment to reassess your RPO and RTO targets. A managed HA replica with automatic 30-second failover, or a PITR fork, may support tighter targets than a self-hosted setup was actually hitting in practice, especially if failover testing on the self-hosted side had been infrequent.