Mneme is a pair of Bash utilities for creating Git-friendly MySQL database snapshots and restoring them later.
mneme-dumpdumps one MySQL database into a stable directory layout: schema files plus one SQL file per table.mneme-restorerestores a Mneme dump into the original database name or a different target database.
The scripts were designed with Moodle-style MySQL 8+ databases in mind, but they can be used with other mostly-InnoDB MySQL databases as well.
THIS SCRIPT IS PROVIDED ON AN "AS IS" BASIS WITHOUT ANY WARRANTIES OF ANY KIND. BY USING THIS SCRIPT, THE USER CONFIRMS THEY HAVE CONDUCTED THEIR OWN DUE DILIGENCE TO VERIFY ITS SUITABILITY AND SAFETY. THE USER VOLUNTARILY ACCEPTS FULL RISK ASSUMPTION FOR ANY DAMAGES OR DATA LOSS ARISING FROM ITS USE.
Important: Mneme is a logical Git-friendly snapshot tool, not a full backup strategy.
I created this tool mainly to assist with taking "diff-able" snapshots of databases then committed to git during development, facilitating rolling back to earlier states, examining database differences when debugging if required, and things of that nature.
While not really intended for backups of application databases for non-development purposes, that is a purpose that I'm interested in looking at though I will probably create an entirely separate tool for that purpose rather than expand this tool.
The name Mneme (pronounced like "nee-me") comes from the Greek concept of memory, which suits a tool that facilitates turning a database state into reviewable historical memory.
Normal mysqldump output is often awkward to review in Git because one large SQL file can mix unrelated changes from many tables. Multi-row INSERT statements also make diffs noisy because a single row change can alter a very long line.
Mneme aims to make database snapshots more reviewable by:
- writing one data file per table;
- omitting volatile dump timestamps;
- ordering rows by primary key where MySQL can do so;
- using one
INSERTstatement per row; - keeping the default dump directory name stable;
- writing simple manifest and diagnostic files.
This makes it easier to review changes such as Moodle configuration changes, plugin upgrade effects, test fixture changes, and pre/post migration database deltas.
A split-table dump is naturally different from a single mysqldump connection.
By default, Mneme dumps each table using its own mysqldump process. Each process uses --single-transaction, which is good for InnoDB table consistency within that process, but separate processes do not automatically share the exact same transaction snapshot.
Recommended modes:
| Situation | Recommended approach |
|---|---|
| Local/dev/staging database that is not being written to | mneme-dump --jobs N |
| Moodle site placed into maintenance/read-only mode | mneme-dump --jobs N |
| Live database where writes may continue and a globally consistent split dump is required | mneme-dump --jobs N --lock-for-consistency |
--lock-for-consistency holds FLUSH TABLES WITH READ LOCK while dumping. That gives a better global point-in-time split dump, but it blocks writes until the dump completes.
- Bash 4.3 or newer.
- MySQL client tools available in
PATH:mysqlmysqldump
- MySQL 8+ recommended.
- Sufficient database privileges for the selected objects:
- base tables;
- triggers, unless
--skip-triggersis used; - routines, unless
--skip-routinesis used; - events, unless
--skip-eventsis used.
The scripts use coloured labels for INFO, WARN, ERROR, FATAL, OK, and DONE messages.
The scripts also include a small local checkerr-compatible helper so they remain self-contained. checkerr.inc.sh is a bash include script I use in a lot of my bash scripts to help both give feedback to the user on success/failure of operations within the script and stop the script running if a fatal failure occurs that subsequent operations might depend on.
Note that if you want to use the original checkerr.inc.sh (rather than the internal 'simple' checkerr compatible function, you can source it by setting CHECKERR_INC:
export CHECKERR_INC=/path/to/checkerr.inc.shPrefer mysql_config_editor login paths or protected option files over command-line passwords.
Example login path:
mysql_config_editor set \
--login-path=moodlebackup \
--host=localhost \
--user=moodleuser \
--passwordThen use:
./mneme-dump --login-path=moodlebackup --database moodledb
./mneme-restore --login-path=moodlebackup --input ./mysql-table-dumps/moodledbEnvironment-variable password use is supported for convenience:
MYSQL_PWD='secret' ./mneme-dump -u moodleuser -d moodledbHowever, --login-path or --defaults-extra-file is preferable.
Basic Git-friendly dump:
./mneme-dump \
--login-path=moodlebackup \
--database moodledb \
--output ./db-dumpsParallel dump with six workers:
./mneme-dump \
--login-path=moodlebackup \
--database moodledb \
--output ./db-dumps \
--jobs 6Parallel dump with a global read lock:
./mneme-dump \
--login-path=moodlebackup \
--database moodledb \
--output ./db-dumps \
--jobs 6 \
--lock-for-consistencySkip selected tables:
./mneme-dump \
--login-path=moodlebackup \
--database moodledb \
--ignore-table mdl_logstore_standard_log \
--ignore-table mdl_task_logBy default, Mneme writes to a stable directory:
./mysql-table-dumps/moodledb/
Use --dated only when you intentionally want archival timestamped directories:
./mneme-dump --login-path=moodlebackup -d moodledb --datedTimestamped directories are less Git-friendly because every run creates a new tree.
A typical dump looks like this:
moodledb/
├── README.md
├── manifest.env
├── tables.tsv
├── diagnostics/
│ └── no_unique_key_tables.txt
├── schema/
│ ├── 00-tables-and-views.sql
│ └── 90-routines-events-triggers.sql
└── tables/
├── mdl_config.sql
├── mdl_course.sql
├── mdl_user.sql
└── ...
Key files:
| Path | Purpose |
|---|---|
manifest.env |
Basic metadata used by the restore script. |
tables.tsv |
Maps original table names to table data files. |
schema/00-tables-and-views.sql |
Table and view definitions. |
tables/*.sql |
Data-only table dumps, one file per base table. |
schema/90-routines-events-triggers.sql |
Routines, events, and triggers, when enabled. |
diagnostics/no_unique_key_tables.txt |
Tables where row order may be less deterministic. |
Tables without a primary key or unique key can still produce noisy diffs because MySQL has no stable key for --order-by-primary to use.
Restore to the database recorded in manifest.env:
./mneme-restore \
--login-path=moodlebackup \
--input ./db-dumps/moodledbRestore into a clean local development database:
./mneme-restore \
--login-path=moodlebackup \
--input ./db-dumps/moodledb \
--database moodle_dev \
--drop-database \
--jobs 6Restore schema and table data, but skip routines/events/triggers:
./mneme-restore \
--login-path=moodlebackup \
--input ./db-dumps/moodledb \
--database moodle_dev \
--drop-database \
--skip-objects--skip-objects is useful when object restore fails due to DEFINER, routine, trigger, event, or privilege issues.
Restore runs in this order:
- create the target database if needed;
- import
schema/00-tables-and-views.sql; - import
tables/*.sql, optionally in parallel; - import
schema/90-routines-events-triggers.sql, unless skipped.
Triggers are imported after table data so they do not fire during the table data reload.
Parallel table import disables FOREIGN_KEY_CHECKS and UNIQUE_CHECKS per import session to reduce dependency-order problems and improve loading performance.
A simple workflow:
./mneme-dump --login-path=moodlebackup -d moodledb -o ./db-dumps -j 6
cd ./db-dumps/moodledb
git status
git diffSuggested .gitignore entries for the repository that stores Mneme output:
# local restore logs
mysql-restore-logs/
# optional compressed/archive files
*.sql.gz
*.sql.bz2
*.tar.gz
# local editor files
.DS_Store
*.swpAvoid compressing the per-table SQL files if your main goal is readable Git diffs.
Useful Moodle tables to consider excluding in review-only snapshots may include very large or high-churn logs, depending on the purpose of the dump:
--ignore-table mdl_logstore_standard_log
--ignore-table mdl_task_logDo not exclude tables blindly for a restore that is meant to reproduce a working Moodle site. Log tables may be optional for many analysis workflows, but other high-volume tables can still be functionally important.
For a Moodle instance in use by more than one user prefer one of these before dumping:
- put Moodle into maintenance mode;
- stop cron and other write-producing integrations temporarily;
- use
--lock-for-consistencyand accept the write-blocking impact; - use Mneme only as a secondary diff artifact, while relying on your normal backup system for disaster recovery.
The dump script uses --no-tablespaces to avoid common MySQL 8 tablespace privilege issues. If you still see privilege errors, check the user’s privileges for the database and selected object types.
Try excluding object types on dump:
./mneme-dump --login-path=moodlebackup -d moodledb --skip-routines --skip-events --skip-triggersOr skip object restore:
./mneme-restore --login-path=moodlebackup -i ./db-dumps/moodledb --skip-objectsCheck:
- whether the table appears in
diagnostics/no_unique_key_tables.txt; - whether the application updates timestamp fields frequently;
- whether the table contains log/session/cache-style data;
- whether volatile tables should be excluded for your review use case.
Restore into a clean database, or use:
./mneme-restore --input ./db-dumps/moodledb --database moodle_dev --drop-databaseie. so you don't inadvertently wreck your dev environment off the bat - I know what a pain it can be to have to set things back up again, so please make sure you know what you're doing and perform some tests before working with it on anything important.
- Run a dump against a disposable development database.
- Restore into a separate disposable database name.
- Compare row counts between source and restored databases.
- Test Moodle (or whatever you're working on) can start against the restored database if that is part of your use case.
- Review
diagnostics/no_unique_key_tables.txt. - Commit only the SQL dump files you intentionally want in Git.
- Do NOT rely on Mneme as your backup plan.
This script is licenced under the GNU Affero General Public License v3.0