Chapter 13 · Backup, mariadb-backup, Restore, and Point-in-Time Recovery

Logical Backup with mariadb-dump: Consistency, Objects, Routines, and Large Databases

Build and verify MariaDB logical backups with consistent snapshots, explicit stored-object coverage, large-table-safe streaming, and restore testing rather than trusting dump-file creation.

Advanced130–160 minutesLogical dump + clean restore labMariaDB Community 12.3.2 baselineCurriculum anchor: 11.8 LTS · verify target versionLast reviewed: August 2026

Learning outcomes

ServiceHub can recreate application binaries from Git, but a recent staging incident exposed a harder question: could the team rebuild the database state after an operator deletes a customer queue? A developer answers, “we have a nightly SQL file.” That is not yet a recovery capability. Nobody has proved whether the file is transactionally consistent, whether stored routines and scheduled events are inside it, whether a schema change can race the dump, or whether the file can actually be imported into a clean MariaDB instance.

A logical backup records database objects as logical SQL or delimited data rather than copying MariaDB's physical data files. mariadb-dump is MariaDB's standard logical-dump client. Logical backups are portable and inspectable, but their correctness depends on storage-engine semantics, the chosen dump options, concurrent Data Definition Language (DDL), object coverage, privileges, character sets and—most importantly—successful restore testing.

01

Explain what --single-transaction guarantees for transactional tables and what it does not guarantee for nontransactional engines or concurrent DDL.

02

Capture tables, triggers, routines and events deliberately instead of assuming every server-side object is included by default.

03

Use row-by-row/streaming behavior suitable for large tables and avoid embedding reusable secrets in command history.

04

Restore a dump into a disposable MariaDB instance and verify row counts, constraints and stored objects.

05

Diagnose a deliberately incomplete dump and repair the backup command from observed restore evidence.

Current baseline

The curriculum retains MariaDB 11.8 LTS as an educational anchor; this chapter uses MariaDB Community 12.3.2 as the current reference baseline. Current mariadb-dump documentation says triggers are dumped with tables by default, while routines and events require explicit options. Always run mariadb-dump --help on the exact client version you are using because dump syntax and output compatibility evolve.

1. Start with the recoverability question, not the dump command

A backup should correspond to a defined recovery promise. For a logical backup, ask: which schemas, objects and data must be reconstructed; what consistency point is required; how much concurrent write activity is allowed; how long may export and import take; and what will prove the result is usable?

Question Why it changes the backup design
Are all tables transactional? --single-transaction uses a consistent transaction snapshot for transactional engines such as InnoDB; it cannot make nontransactional tables participate in that snapshot.
Can DDL occur? ALTER/DROP/RENAME/CREATE operations can invalidate assumptions while the dump is running. A transaction snapshot is not a general “schema freeze.”
Are routines/events required? They need explicit coverage. A data restore that silently omits server-side behavior is incomplete.
How large are the tables? mariadb-dump is normally single-threaded and performs table scans; storage and network I/O can dominate.
How will the dump be verified? File existence and exit code prove export completion, not recovery correctness.

2. Build a disposable ServiceHub logical-backup lab

Run the following only on a disposable local MariaDB Community instance. The lab uses InnoDB so the mandatory consistency experiment does not depend on optional storage engines. A trigger, stored procedure and event make object coverage observable.

sql · create data and server-side objects
DROP DATABASE IF EXISTS servicehub_recovery_lab;CREATE DATABASE servicehub_recovery_lab  CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;USE servicehub_recovery_lab;CREATE TABLE tickets (  ticket_id BIGINT PRIMARY KEY,  customer_name VARCHAR(120) NOT NULL,  status ENUM('open','assigned','closed') NOT NULL,  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP             ON UPDATE CURRENT_TIMESTAMP) ENGINE=InnoDB;CREATE TABLE ticket_audit (  audit_id BIGINT AUTO_INCREMENT PRIMARY KEY,  ticket_id BIGINT NOT NULL,  old_status VARCHAR(20),  new_status VARCHAR(20),  changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB;DELIMITER //CREATE TRIGGER tickets_auAFTER UPDATE ON ticketsFOR EACH ROWBEGIN  IF NOT (OLD.status <=> NEW.status) THEN    INSERT INTO ticket_audit(ticket_id, old_status, new_status)    VALUES(NEW.ticket_id, OLD.status, NEW.status);  END IF;END//CREATE PROCEDURE close_ticket(IN p_ticket_id BIGINT)BEGIN  UPDATE tickets SET status='closed' WHERE ticket_id=p_ticket_id;END//DELIMITER ;CREATE EVENT IF NOT EXISTS ev_recovery_markerON SCHEDULE EVERY 1 DAYDO INSERT INTO ticket_audit(ticket_id, old_status, new_status)   VALUES(0, 'event', 'marker');INSERT INTO tickets(ticket_id,customer_name,status) VALUES(3001,'Northwind Clinic','open'),(3002,'Alpine Support','assigned'),(3003,'Contoso Field Ops','open');CALL close_ticket(3003);

Inspect what exists before backup. This pre-backup inventory becomes the restore acceptance baseline.

sql · capture pre-backup evidence
SELECT COUNT(*) AS ticket_rows FROM servicehub_recovery_lab.tickets;SELECT COUNT(*) AS audit_rows FROM servicehub_recovery_lab.ticket_audit;SHOW TRIGGERS FROM servicehub_recovery_lab;SHOW PROCEDURE STATUS WHERE Db='servicehub_recovery_lab';SHOW EVENTS FROM servicehub_recovery_lab;SHOW CREATE TABLE servicehub_recovery_lab.tickets\G

Expected state: three ticket rows, at least one audit row from the procedure-driven update, one trigger, one procedure and one event. The exact timestamps and metadata formatting vary. This evidence proves the source objects existed; it does not prove the backup captured them.

3. Understand --single-transaction precisely

With InnoDB, --single-transaction starts a transaction with a consistent snapshot so rows read later in the dump can represent the same logical point even while ordinary DML continues. This is far less disruptive than locking every InnoDB table for the full export. The property comes from InnoDB multi-version concurrency control (MVCC), not from magic inside the output file.

Boundary that matters

--single-transaction is not a guarantee for MyISAM, Aria configured/used as nontransactional data, or other nontransactional engines. It also does not make arbitrary concurrent DDL safe. If mixed engines or schema changes must be captured as one coordinated state, design an explicit maintenance/locking strategy and test it on the exact topology.

If you want to study the mixed-engine boundary, first run SHOW ENGINES. Only if a nontransactional engine is supported in your local build, create a disposable table with that engine and observe that a transaction snapshot does not roll its changes back or version them like InnoDB. Do not make optional-engine behavior a production assumption merely because CREATE TABLE succeeds.

4. Create a deliberate, self-describing dump

Use an option file or another secret mechanism appropriate to your environment rather than placing reusable passwords in shell history. The command below assumes authentication is already configured securely. --quick retrieves rows incrementally instead of buffering an entire table in client memory; current --opt enables it by default, but spelling it out here documents intent.

shell · logical backup suitable for the lab
mkdir -p ./servicehub-backupsmariadb-dump \  --single-transaction \  --quick \  --routines \  --events \  --triggers \  --master-data=2 \  servicehub_recovery_lab \  > ./servicehub-backups/servicehub_recovery_lab.sql

--master-data=2 records binary-log coordinates as comments when binary logging is enabled and is useful when this dump becomes the base of point-in-time recovery. Combined with --single-transaction, MariaDB can coordinate the snapshot and log position for InnoDB-oriented online backup. If binary logging is disabled, do not invent coordinates; Lesson 3 builds the PITR prerequisite deliberately.

Record tool and server versions next to the artifact:

shell · record backup provenance
mariadb-dump --versionmariadb --versionmariadb -Nse "SELECT VERSION();"wc -c ./servicehub-backups/servicehub_recovery_lab.sql

On Windows PowerShell, use the same MariaDB client executable but redirect explicitly:

powershell · PowerShell equivalent
New-Item -ItemType Directory -Force .\servicehub-backups | Out-Nullmariadb-dump --single-transaction --quick --routines --events --triggers --master-data=2 servicehub_recovery_lab |  Set-Content -Encoding utf8 .\servicehub-backups\servicehub_recovery_lab.sqlmariadb-dump --versionmariadb --version
Encoding note

For production automation, prefer binary-safe redirection behavior verified for your shell/client combination. PowerShell version and encoding defaults differ. A restore drill is the authoritative test; do not assume a text file is byte-for-byte suitable merely because it looks readable.

Compression can reduce transfer/storage bytes, but a pipeline must propagate failures from both the dump and compressor. On POSIX shells, enable a failure mode such as set -o pipefail when supported, and verify the resulting compressed stream before promotion:

shell · compressed logical stream with failure-aware shell
set -o pipefailmariadb-dump --single-transaction --quick --routines --events --triggers servicehub_recovery_lab   | gzip -c > ./servicehub-backups/servicehub_recovery_lab.sql.gzgzip -t ./servicehub-backups/servicehub_recovery_lab.sql.gz

Do not assume database users and roles belong inside the same application-data dump. Account definitions, authentication plugins, password hashes and grants are security configuration and can be version/platform sensitive. Inventory them separately with SHOW CREATE USER/SHOW GRANTS for the accounts you actually intend to recover, or use a current MariaDB-supported system-account export method after verifying it on the target release. Avoid copying raw mysql.* system tables across major versions as a generic migration technique.

sql · separate security-principal evidence
SHOW CREATE USER 'mariadb_backup'@'localhost';SHOW GRANTS FOR 'mariadb_backup'@'localhost';-- Repeat only for explicitly managed accounts/roles that belong in the recovery plan.

A safe restore order is deliberate: create/verify the target server baseline; restore required account/role/definer identities or intentionally rewrite definers; restore schemas/tables/data; recreate routines/triggers/events/views in dependency order; then enable schedules/application traffic only after validation. A single dump file may automate much of that order, but the runbook must still account for external identities, secrets, plugins and definers.

5. Deliberately make an incomplete backup, then diagnose it

A common failure is to assume “dump database” means “dump every executable object.” Create a second dump without routine/event options:

shell · intentionally incomplete export
mariadb-dump --single-transaction --quick servicehub_recovery_lab   > ./servicehub-backups/incomplete.sqlgrep -n "CREATE.*PROCEDURE\|CREATE.*EVENT\|TRIGGER"   ./servicehub-backups/incomplete.sql || true

The trigger may still be present because triggers are dumped with their tables by default, while the procedure and event are absent unless requested. That is the important lesson: backup completeness is object-type-specific. The repair is not “hope the defaults are enough”; it is an explicit command plus restore acceptance tests.

A second misleading approach is to run long schema migrations during a dump because “single transaction means frozen database.” The data snapshot and schema metadata are different concerns. Coordinate DDL through deployment controls or a defined backup window, and monitor dump errors rather than suppressing them with --force.

6. Restore into a disposable second instance and prove the result

Never test restore by overwriting the only copy of the source. Use a second local MariaDB instance of the same baseline—another service/data directory or a disposable container. The container example is optional in tooling choice but remains free/local; use port 3307 to avoid colliding with the source.

shell · example disposable restore target
docker run --name servicehub-restore -d \  -e MARIADB_ROOT_PASSWORD='lab-only-change-me' \  -p 3307:3306 mariadb:12.3.2# Wait until the server reports ready, then create the target schema.mariadb -h 127.0.0.1 -P 3307 -u root -p   -e "CREATE DATABASE servicehub_recovery_lab;"mariadb -h 127.0.0.1 -P 3307 -u root -p   servicehub_recovery_lab   < ./servicehub-backups/servicehub_recovery_lab.sql

If Docker/Podman is unavailable, initialize a second local MariaDB data directory/service on a different port/socket following your operating-system package instructions. The critical property is isolation, not the container product.

sql · restore acceptance checks
SELECT COUNT(*) AS ticket_rows FROM servicehub_recovery_lab.tickets;SELECT COUNT(*) AS audit_rows FROM servicehub_recovery_lab.ticket_audit;SHOW TRIGGERS FROM servicehub_recovery_lab;SHOW PROCEDURE STATUS WHERE Db='servicehub_recovery_lab';SHOW EVENTS FROM servicehub_recovery_lab;CALL servicehub_recovery_lab.close_ticket(3002);SELECT ticket_id,status FROM servicehub_recovery_lab.tickets ORDER BY ticket_id;

Compare those results with the source inventory captured before backup. A successful import with missing routines is still a failed recovery if the application depends on those routines. Likewise, equal row counts do not prove semantic equality; add domain-specific checks such as sums, foreign-key integrity, known business invariants and sampled hashes where appropriate.

7. Large databases: throughput is part of recoverability

Logical dumps scan and serialize data. On large databases, export duration, restore duration, network throughput, disk contention, undo retention pressure from a long consistent snapshot, and single-threaded restore characteristics can dominate. MariaDB versions from 11.5 add newer directory/parallel dump capabilities; treat those as version-gated features and verify exact syntax with your client. Do not claim a universal throughput gain.

Signal What to measure Why
Dump duration wall clock + source I/O Long snapshots can retain older row versions and compete with workload I/O.
Artifact size bytes + compression ratio Determines transfer/storage cost but not restore speed by itself.
Restore throughput rows/bytes per minute on restore hardware RTO is constrained by import and validation, not export alone.
Error log/client exit nonzero exit + warnings Partial dumps must not be promoted as valid artifacts.

8. Production judgment and cleanup

Choose logical backup when inspectability, migration/portability, object-level recovery or selective transformation matters and the measured export/restore time fits objectives. Prefer physical backup for very large same-engine/server recoveries when file-level restore is materially faster; Lesson 2 teaches that path. Many production strategies use both.

Protect dump files as production data. They can contain credentials, personal data, definers and sensitive SQL. Encrypt at rest, restrict filesystem/object-store access, keep integrity metadata, and retain copies away from the database host. Do not delete source binlogs after a dump until the recovery policy proves they are no longer required.

sql · lab cleanup
DROP DATABASE IF EXISTS servicehub_recovery_lab;
shell · remove disposable container only after verification
docker rm -f servicehub-restore  # only if this lab created it

Check your understanding

  1. Why does --single-transaction work well for an InnoDB-only logical backup but not guarantee consistency for nontransactional tables?
  2. Which server-side object classes need explicit mariadb-dump options in this lesson?
  3. Why is a successful mariadb-dump exit insufficient evidence of recoverability?
  4. What can concurrent DDL invalidate even when a consistent data snapshot exists?
  5. Why should restore duration be measured during normal backup engineering rather than during an incident?
Review the answers

InnoDB can expose a consistent MVCC snapshot inside one transaction, while nontransactional engines do not participate in that snapshot. Routines and events require explicit coverage; triggers are normally included with table definitions. Export success proves only that the tool produced output, not that all required objects/data can be restored. DDL can change metadata/object definitions independently of the row snapshot. Restore duration determines whether the recovery time objective is realistic and must be learned before an outage.

Next, move from logical SQL to physical page/file backup. The mental model changes: mariadb-backup copies a live data directory while coordinating with the server, and the raw copy must be prepared before it becomes a consistent restore candidate.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.