Conceptual editorial illustration
AI-generated editorial illustration. The measurements and experiment results are presented separately below.

A successful copy command answers a small question: did some bytes reach a destination? It does not tell you whether those bytes contain a consistent database, or whether the data you care about can be read from them.

We ran an isolated demonstration using Python's SQLite backup API, then opened a restored copy and compared its contents with a baseline. The script creates its own synthetic database. It does not open any production database.

What passed: the restored database returned integrity_check = ok, contained 1,001 rows, and matched the baseline content digest. The original contained 1,002 rows after a later commit. This was a local demonstration, not a concurrent-writer stress test.

What we actually tested

ConditionValue
Operating systemWindows
Python / SQLite3.11.9 / 3.45.1
Journal modeWAL
Writer connectionKept open during backup
Concurrent write workloadNot tested
DataSynthetic notes only

The test ran on November 1, 2026. The exact runtime versions, counts and matching digests are in the downloadable result.

The sequence matters

  1. Create a new database in a uniquely named experiment directory and enable WAL mode.
  2. Insert 1,001 synthetic rows, commit, and record an ordered content digest.
  3. Use Connection.backup() to write a second database while the source connection remains open.
  4. Commit one more row to the source, after the backup completes.
  5. Copy the completed backup to a restore-test file and open that file independently.
  6. Check integrity, row count, and the ordered content digest.

The restored copy correctly contains the earlier 1,001-row state. The later row is absent because it was committed after the backup. This small distinction makes the result easier to interpret than a generic “backup succeeded” message.

Run the isolated example

Download the Python demonstration, inspect it, and choose a new output directory:

python sqlite_backup_demo.py --out ./backup-experiment

Each run creates a unique subdirectory. Python's standard library is enough. Your operating system and SQLite version may differ; the script records them in its result instead of assuming ours.

with sqlite3.connect(source) as writer:
    # Commit the state you want to verify first.
    with sqlite3.connect(backup) as destination:
        writer.backup(destination)

with sqlite3.connect(restored) as checked:
    integrity = checked.execute(
        "PRAGMA integrity_check"
    ).fetchone()[0]

Use more than an integrity check

The integrity check asks whether the database's internal structure is consistent. Our row count and digest ask whether this synthetic dataset matches the baseline. A production restore test should also exercise application-specific reads and the permissions, dependencies and steps needed to bring the application back.

For a WAL database, copying only the main database file while it is being written can miss relevant state in the journal files. Use an appropriate SQLite backup mechanism and test the result. This demonstration is not instructions to copy a running production file directly.

What this does not prove

We did not test writes occurring concurrently with the backup, interruption halfway through, disk failure, remote storage, encryption keys, a large database or the recovery of a real application. Those are separate experiments. A verified synthetic restore is a useful beginning, not a complete disaster-recovery plan.

Sources and files