Self-Hosted Database Upgrade Guide: Dump, Snapshot, Migrate, and Roll Back

Eva Wong is the Technical Writer and resident tinkerer at ZimaSpace. A lifelong geek with a passion for homelabs and open-source software, she specializes in translating complex technical concepts into accessible, hands-on guides. Eva believes that self-hosting should be fun, not intimidating. Through her tutorials, she empowers the community to demystify hardware setups, from building their first NAS to mastering Docker containers.

The safe approach is to treat a staged upgrade using native dumps, storage snapshots, isolated restore rehearsal, and a clearly bounded rollback point as a sequence of observable gates, not a single command.

On a containerized PostgreSQL or MariaDB database on a home server, the practical risk is a self-hosted database needs a version upgrade without losing logical objects or a viable rollback path. Record the current identity and recovery point, start with the least invasive discriminator, interpret pass and fail results before changing another variable, and stop when storage becomes unstable or the only recoverable copy would be exposed. The workflow below ends only after the original workload succeeds or the evidence reaches an escalation boundary.

Define compatibility and rollback before backup

Record database engine and exact source version, target version, application version, extensions or plugins, character set, authentication rules, scheduled jobs, and available downtime. Read the applicationโ€™s upgrade notes as well as the database path because an application migration can make old binaries incompatible with the new schema.

Major upgrades often require a logical dump and restore or a supported migration tool rather than mounting the old data directory in a new image. An independent Compose database major upgrade workflow walks through a Compose-based PostgreSQL major upgrade and shows why the old container and volume must remain distinct from the target.

Write the rollback deadline and trigger now: failed integrity checks, missing roles or extensions, application errors, or unacceptable performance. Rollback remains viable only until production writes begin on the target unless a reverse data-migration plan has been tested.

Create two independent recovery points

Run the engine-native logical backup with global objects where applicable, then save the command, version, exit status, manifest, and checksum. Verify that users, grants, extensions, schemas, scheduled jobs, and large objects are included instead of assuming one database dump contains every server-level dependency.

Take a coordinated snapshot or stopped copy of the database volume after confirming the database is in a supported state. The logical dump provides portability and object-level inspection; the storage copy preserves an exact old-version rollback point. Neither should overwrite the other.

Use the ZimaSpace verification checklist for whether database backup completeness checklist. The backup gate passes only when the dump is readable, the storage recovery point is identified, and both are stored outside the volume being upgraded.

Rehearse migration in an isolated target

Start the target database on a separate volume and port, install required extensions, restore the logical backup, and save every warning. A Percona walkthrough of logical dump and restore upgrade path highlights the dump-and-restore sequence and the need to use tools that match the intended PostgreSQL upgrade path.

Connect a disposable application instance to the restored database. Test login, reads, writes, background jobs, search, attachments, time zones, and a restart. Compare row counts and critical aggregates instead of relying on a successful restore exit code alone.

Do not proceed if extensions are unavailable, collation changes are unresolved, migrations fail, or restore time exceeds the maintenance window. Fix the rehearsal and create a fresh dump; production is not the place to discover target-version incompatibility.

Cut over writes and keep rollback clean

Enter maintenance mode, stop application writers and jobs, confirm active connections drain, then create the final dump or supported delta. Restore it to a clean target, run integrity and object checks, update the application connection, and start services in dependency order.

Observe error rates, locks, job execution, backups, and real application transactions. Keep the old database stopped and read-only with its original volume and image digest. Never let both databases accept independent writes under the same application identity.

Declare success only after the application, native backup job, restart, and a test restore from the new version all pass. If a rollback trigger fires before the write boundary, point the app back to the preserved old instance; after new writes, stop and use the documented reconciliation plan rather than pretending a simple restart reverses data.

Support & Tips

More to Read

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.