Recovering data from a corrupt SQLite file is less about fixing the broken file and more about extracting everything readable from it into a fresh, healthy database. Once SQLite reports database disk image is malformed, the original file is no longer trustworthy as a whole, but the data inside it is usually far from lost. A database is a single file of fixed-size B-tree pages, and corruption typically damages a few of those pages while leaving the rest sound. Recovery is the disciplined process of reading every good page and rewriting its contents somewhere safe.

This guide explains how that salvage actually works under the hood so you can reason about what to expect. You will see the role of the schema table, how the .recover and .dump commands differ, what partial recovery means in practice, and how to export individual tables. To do the salvage without a terminal, the repair SQLite tool performs the whole process in your browser and hands back a rebuilt file.

The Schema Table Is Where Recovery Begins

Every SQLite database carries its own map. A hidden system table named sqlite_master sits at the very start of the file and records the schema: one row for every table, index, view, and trigger, each holding the original CREATE statement and the page number where that object's B-tree begins. When you open a database, SQLite reads sqlite_master first, learns what tables exist, and then knows which pages to walk to find their rows.

Recovery leans on this same map. If sqlite_master is intact, a recovery tool can read the list of tables, recreate each one with its stored CREATE statement, and then chase down the rows tree by tree. If sqlite_master itself is damaged, the situation is harder but not hopeless: modern recovery can scan the raw pages of the file looking for anything that resembles a table B-tree, reconstructing structure from the fragments even when the official schema is gone. This is the key advantage of a purpose-built recovery pass over a naive read.

How .recover Salvages Rows

The sqlite3 command line ships two salvage commands, and understanding the difference tells you which to reach for. The stronger of the two is .recover:

  • Run sqlite3 broken.db ".recover" | sqlite3 recovered.db.
  • Instead of trusting the database to open cleanly, .recover reads the file at the page level. It reconstructs the schema from whatever survives, then extracts row data directly from the B-tree pages, emitting a stream of SQL CREATE and INSERT statements.
  • That SQL stream is piped into a brand-new database, which is built from scratch and is therefore structurally perfect.
  • Because it works from raw pages and keeps going past damaged regions, .recover can salvage data that a normal read would refuse to touch. It even collects orphaned rows, records whose parent table pointer is broken, into a special recovery table so you do not silently lose them.

The output is a clean database rebuilt entirely from salvaged content. Nothing modifies the corrupt original, so you can rerun the process safely.

How .dump Compares

The older .dump command serialises an entire database to SQL text: sqlite3 broken.db ".dump" | sqlite3 recovered.db. It is excellent when a file still opens and only a few rows are affected, because it produces a complete, human-readable transcript of the schema and data. Its limitation is that it reads the database the normal way, so it tends to stop at the first serious corruption it hits, potentially leaving later tables unexported. For a genuinely malformed file, .recover is the more resilient choice; keep .dump for lightly damaged or healthy databases you simply want to export.

What Partial Recovery Really Means

Recovering data from a corrupt SQLite file is an exercise in salvaging what physically survives, so it is important to be realistic about outcomes. Three principles govern how much you get back:

  • Readable pages come back in full. If a table's B-tree pages are undamaged, every row on them is recovered exactly.
  • Damaged pages are skipped. Rows that lived only on corrupt pages cannot be rebuilt, because their bytes are unreadable. A large table might return thousands of rows and quietly lose a handful from the one bad page.
  • Truncated files stop where the data stops. If the file was cut short, recovery salvages everything up to the truncation point and no further, since the missing pages were never written.

After any recovery, verify the result by running PRAGMA integrity_check on the new database and spot-checking row counts against what you expect. A returned value of ok means the rebuilt file is structurally sound, even if a few rows from the worst-hit pages did not survive.

Exporting Individual Tables

Sometimes you do not need the whole database back, only one critical table. Recovery makes this straightforward because the salvaged data is plain SQL. After a .recover into a clean database, you can export any single table to a portable format:

  • To CSV: in the sqlite3 shell, run .headers on, .mode csv, .output orders.csv, then SELECT * FROM orders;. You now have a plain file you can open anywhere or load elsewhere.
  • To SQL: run .dump orders to emit just that table's CREATE and INSERT statements, ready to replay into another database.

This table-level export is invaluable when a single high-value table, such as a users or transactions table, matters more than the rest of the schema. It lets you rescue the data that counts and rebuild the surrounding structure at your own pace.

Doing It Without a Terminal

If you would rather not touch the command line, the repair SQLite tool automates the entire flow. Upload the corrupt file and it reads sqlite_master, walks each B-tree, salvages every readable row, collects orphaned records, and writes a fresh, valid database you can download. Remember to include the companion -wal and -shm files if the database used WAL mode, since recent committed changes may still live there rather than in the main file. For the full workflow around this, see our guide on how to repair a corrupted SQLite database.

Conclusion

Recovering data from a corrupt SQLite file works because the file is a collection of B-tree pages mapped by sqlite_master, and damage is almost always local. A recovery pass reads the surviving pages, rebuilds the schema, salvages every readable row (including orphaned ones), and writes a clean database from the results. Use .recover for badly damaged files, .dump for lightly damaged ones, and export individual tables to CSV or SQL when a single table is all you need. Always confirm the rebuilt file with PRAGMA integrity_check. To salvage yours now, open the repair SQLite tool, and read why SQLite databases get corrupted to stop it happening again.