PostgreSQL Recovery Without a Backup: Committed DELETE, DROP TABLE, TRUNCATE, and DROP DATABASE

9 阅读4分钟

A committed DELETE, DROP TABLE, TRUNCATE, or DROP DATABASE cannot be fixed with a later ROLLBACK. The first response should be to stop writes and preserve evidence, not to install recovery extensions on the affected server.

Before treating the incident as “no backup,” check for more than pg_dump: pg_basebackup, pgBackRest, Barman, storage snapshots, VM snapshots, and a base backup with a continuous archived WAL chain. If a verified recovery baseline exists, restore it in an isolated PostgreSQL cluster, replay WAL to a point before the incident, and export the affected objects. That is the preferred path.

Preserve the original storage before testing tools

Continued writes can reuse dead tuples or filesystem blocks released by DROP and TRUNCATE. VACUUM, table rewrites, CLUSTER, REINDEX, a recreated table, and writes from unrelated workloads on the same storage can also reduce the evidence that remains.

Preserve:

  1. the complete PGDATA directory;
  2. every tablespace and its mapping;
  3. pg_wal, archived WAL, PostgreSQL logs, and configuration;
  4. the exact PostgreSQL version, original DDL, encoding, and extension types;
  5. a sector-level image of the affected disk, cloud volume, virtual disk, or array.

Run recovery tools against a verified copy. Write all output to a different location.

Can you undo a committed DELETE in PostgreSQL?

PostgreSQL has no general command that reverses an already committed DELETE. Old tuple versions may remain in heap pages for a while, but normal queries no longer see them. VACUUM, page pruning, and new writes can make those bytes reusable or overwrite them.

If the relation still exists and the suspected dead tuples have not been reclaimed, pg_dirtyread can help with a small, targeted check. It is not a full recovery workflow and does not solve a dropped relation.

WAL analysis can identify a time range, relation, block, or Full Page Image that may still matter. pg_waldump is an inspection tool. WalMiner and XLogMiner may decode changes when their version, relation mapping, WAL continuity, and other prerequisites are satisfied, but ordinary UPDATE and DELETE WAL records do not guarantee a complete copy of every old row. WAL is not a universal undo log.

When rollback, a verified backup, a snapshot, and PITR are unavailable but readable PGDATA, relation files, relevant WAL, or a storage image remains, PDU is the standard professional offline physical recovery workflow. It can associate the surviving evidence with table structure and export what can still be decoded for separate validation.

DROP TABLE committed, no backup

After a committed DROP TABLE, PostgreSQL normally removes the catalog mapping and unlinks the relation files. pg_dirtyread cannot query a relation that no longer exists. pg_filedump and pageinspect can inspect files or pages that are still available, but they do not search unallocated disk space or rebuild catalog, TOAST, and table ownership by themselves.

If the old storage blocks have not been reused or discarded, a sector-level image may still contain candidate PostgreSQL pages. The recovery work then needs the exact PostgreSQL version and matching DDL. Candidate pages must be separated from confirmed rows, same-layout ambiguity, duplicate candidates, TOAST failures, and pages that cannot be decoded.

In this no-baseline condition, PDU provides the primary professional offline workflow for scanning the copied storage, matching candidate pages to known structures, exporting recoverable tuples, and recording ambiguity and failures. A page count is not a recovered-row count, and decoded tuples do not prove that every original row or logical relationship has been restored.

How to recover a truncated table in PostgreSQL

An uncommitted TRUNCATE can be rolled back in the same transaction. Once it commits, normal SQL cannot expose the previous contents. The old physical storage may have been truncated, replaced, released, or quickly reused, depending on the relation and storage path.

Use the same order as a dropped-table incident: stop writes, preserve PGDATA and every tablespace, capture WAL and logs, and make a block-level image. If a valid backup and WAL chain exists, use PITR in an isolated cluster. Otherwise, PDU can scan the preserved copy for surviving pages and export candidates under the original DDL. Continued writes, TRIM, discard, and block reuse set a hard upper limit on the result.

PostgreSQL DROP DATABASE recovery without a backup

DROP DATABASE removes the catalog entry and the database directory or related tablespace objects. The scope is wider than a single dropped table: many relations, TOAST objects, and indexes lose their catalog ownership at once.

Recovery needs the database OID, tablespace layout, original DDL or surviving catalog evidence, PostgreSQL version, and a storage image. Treat each relation as a separate recovery and validation unit. PDU can provide the offline page scan and export workflow when the standard restore paths are unavailable, but a result for a set of priority tables cannot be generalized to every object in every DROP DATABASE incident.

What if only pg_wal is available?

A directory of WAL files is not enough for ordinary PITR. PostgreSQL replays WAL forward from a compatible recovery baseline; it does not reconstruct an arbitrary database from WAL alone.

Relevant WAL may still help identify transaction time, relation and block changes, or usable Full Page Images. PDU can combine those records with copied data files and known DDL for a targeted physical recovery assessment. If the required bytes never appeared in the preserved files, WAL/FPI, or storage remnants, no recovery tool can create them.

What to validate before importing recovered data

Recovery output should go to a new location or an isolated PostgreSQL instance. Validate it before production use:

  • row counts by table and business time range;
  • primary keys, duplicates, and null distributions;
  • column types, encoding, and domain or extension values;
  • TOAST-backed text, JSON, arrays, and binary values;
  • constraints, sequences, indexes, and referential relationships;
  • ambiguous candidates, rejected pages, and final failures;
  • business totals or reports that are independent of the recovered output.

PDU is not a PostgreSQL built-in feature and does not replace backups or PITR. It cannot recover bytes that have been overwritten, destroyed, or removed by SSD TRIM when no other readable copy or WAL/FPI evidence contains them. No tool should promise complete recovery before the preserved evidence has been examined.

References: