---
id: platform/recovery-postgres
title: "Recovery drill: Postgres"
description: Recover a CNPG object-store archive into a new restore-* namespace and verify with a SQL query.
keywords: [bex, recovery, postgres, cnpg, wal]
last_updated: 2026-09-23
---

# Recovery drill: Postgres

Use `scripts/restore-postgres.sh` (see [Platform recovery rehearsals](./recovery.md)).
The source Cluster and ObjectStore are **read-only**. The target is always a
new `restore-*` namespace whose recovery Cluster has no backup plugin, so it
cannot write back to the source archive identity.

## Prepare

- `--source-namespace`, `--source-cluster`, `--object-store`, `--server-name`
- `--database` and a `--query` (optional `--expect`) that proves data presence
- Optional `--target-time` (RFC3339) for point-in-time recovery when WAL allows
- Reader credentials: per-store overrides when configured; otherwise the
  scripted pre-migration fallback may apply — confirm against your ObjectStore

## DRY_RUN

```bash
cd /path/to/bex
DRY_RUN=1 scripts/restore-postgres.sh \
  --source-namespace bex-system \
  --source-cluster control-plane \
  --object-store backups \
  --server-name control-plane \
  --target-namespace restore-pg-drill \
  --database bex \
  --query "select 1"
```

## Restore

```bash
scripts/restore-postgres.sh \
  --source-namespace bex-system \
  --source-cluster control-plane \
  --object-store backups \
  --server-name control-plane \
  --target-namespace restore-pg-drill \
  --database bex \
  --query "select count(*) from schema_migrations" \
  --expect 1 \
  --confirm restore-pg-drill \
  --teardown-on-success
```

Referenced S3 Secrets are copied into the throwaway namespace without printing
values.

## Verify and clean up

Confirm the SQL expectation. Tear down with
`--teardown restore-pg-drill --confirm restore-pg-drill` when finished. This
does not restore live application connection strings or DNS.
