
MariaDB Backup to S3
Automated MariaDB backups with S3-compatible storage support.
Physical (mariadb-backup) or logical (mariadb-dump) backups, compressed, optionally encrypted, stored locally or in S3/FTP.
Download
·
Report Bug
·
Request Feature
About The Project
MariaDB Backup to S3 is a CLI tool that backs up MariaDB databases, compresses them, optionally encrypts them with AES-256-GCM, and uploads to S3-compatible, FTP, or local filesystem storage.
Two backup methods are supported:
| Method |
Binary |
Description |
| Physical (default) |
mariadb-backup |
Hot backup at the storage engine level. Produces a tar.gz archive. Restore by copying files back to the data directory. |
| Logical |
mariadb-dump |
SQL dump of each database as a separate .sql file, tarred together. Restore by importing the .sql files you need. |
Key features:
- Compress backups with pigz (parallel gzip)
- Optional AES-256-GCM client-side encryption
- Multiple storage backends: S3-compatible, FTP, filesystem
- Automatic backup rotation with configurable retention policies
- Backup registry for tracking and managing backups
- Built-in scheduler daemon for automated scheduled backups without external cron
- Docker container support
(back to top)
Built With
(back to top)
Getting Started
Prerequisites
- Go 1.25+ (for building from source)
- MariaDB server with
mariadb-backup (for physical) or mariadb-dump (for logical) available in PATH, and mariadb client binary for listing databases (logical backup only)
pigz in PATH
tar in PATH
- At least 2x the database size in free temp space
- Storage backend credentials (depending on chosen storage type)
Installation
Binary (recommended):
- Visit the Releases page
- Download the appropriate binary for your OS
- Make executable and move to PATH:
chmod +x mariadb-backup-s3
sudo mv mariadb-backup-s3 /usr/local/bin/
Go install:
go install github.com/capcom6/mariadb-backup-s3@latest
Docker:
docker pull ghcr.io/capcom6/mariadb-backup-s3:latest
Note
The Docker image uses MariaDB's lts version. For specific versions, clone the repo, modify Dockerfile.goreleaser base image, and build a custom image.
From source:
git clone https://github.com/capcom6/mariadb-backup-s3.git
cd mariadb-backup-s3
go build -o mariadb-backup-s3
(back to top)
Usage
mariadb-backup-s3 [global options] command [command options] [arguments...]
Configuration is loaded from (highest priority first): CLI flags > environment variables > .env file in the current directory.
Backup
mariadb-backup-s3 backup [options]
Options:
| Option |
Env Var |
Description |
Default |
| Database |
|
|
|
--db-host, --host |
MARIADB__HOST |
MariaDB hostname |
localhost |
--db-port, --port |
MARIADB__PORT |
MariaDB port |
3306 |
--db-user, --user |
MARIADB__USER |
MariaDB username |
root |
--db-password, --password |
MARIADB__PASSWORD |
MariaDB password |
"" |
--backup-method |
MARIADB__BACKUP_METHOD |
mariadb-backup (physical) or mariadb-dump (logical) |
mariadb-backup |
--db-backup-binary |
MARIADB__BACKUP_BINARY |
Backup binary path |
auto-derived from --backup-method |
--db-client-binary |
MARIADB__CLIENT_BINARY |
mariadb client binary (lists databases for logical backup) |
mariadb |
--db-backup-options |
MARIADB__BACKUP_OPTIONS |
Extra backup options |
"" |
| Storage |
|
|
|
--storage-url, --storage |
STORAGE__URL |
Storage URL (see Storage Types) |
required |
| Encryption |
|
|
|
--encryption-key |
ENCRYPTION__KEY |
Base64-encoded AES-256 key |
"" |
| Retention |
|
|
|
--retention-count |
RETENTION__COUNT |
Number of backups to retain (0 = unlimited) |
0 |
--max-age |
RETENTION__MAX_AGE |
Maximum age of backups (e.g. 24h, 168h) |
unlimited |
--keep-daily |
RETENTION__KEEP_DAILY |
Number of daily backups to keep |
0 (disabled) |
--keep-weekly |
RETENTION__KEEP_WEEKLY |
Number of weekly backups to keep |
0 (disabled) |
--keep-monthly |
RETENTION__KEEP_MONTHLY |
Number of monthly backups to keep |
0 (disabled) |
--skip-retention |
BACKUP__SKIP_RETENTION |
Skip retention policy after backup |
false |
Physical backup example:
mariadb-backup-s3 backup \
--db-host=mariadb.example.com \
--db-user=backup \
--storage-url="s3://my-bucket/backups?endpoint=https://s3.eu-west-1.amazonaws.com" \
--retention-count=14 \
--keep-daily=7
Logical backup example:
mariadb-backup-s3 backup \
--backup-method=mariadb-dump \
--db-host=mariadb.example.com \
--db-user=backup \
--storage-url="s3://my-bucket/backups"
By default mariadb-dump locks tables per database using READ LOCAL locks, so concurrent inserts into non-transactional tables (e.g. MyISAM/Aria) may still occur while a table is dumped, and cross-database consistency is not guaranteed. Each database is dumped in a separate invocation, so the generated .sql files are not point-in-time consistent with each other; as a result, logical (mariadb-dump) backups do not provide a global snapshot of all databases. The virtual schemas information_schema and performance_schema are skipped. For non-blocking dumps (InnoDB only), use --db-backup-options="--single-transaction", accepting that non-transactional tables are then not guaranteed consistent.
Environment-only (minimal):
export MARIADB__HOST=localhost
export MARIADB__USER=root
export MARIADB__PASSWORD=secret
export MARIADB__BACKUP_METHOD=mariadb-backup
export STORAGE__URL=s3://my-bucket/backups
export AWS_REGION=eu-west-1
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=yyy
mariadb-backup-s3
(back to top)
Restore
mariadb-backup-s3 restore [options] [backup_name.tar.gz | --latest | --backup-id=<id>]
Exactly one backup selector must be specified: a filename argument, --latest, or --backup-id.
Options:
| Option |
Env Var |
Description |
Default |
--storage-url, --storage |
STORAGE__URL |
Storage URL |
required |
--encryption-key |
ENCRYPTION__KEY |
Encryption key |
"" |
--target-dir |
RESTORE__TARGET_DIR |
Target directory to restore to |
required |
--latest |
|
Restore latest ready backup from registry |
false |
--backup-id |
|
Restore backup by registry ID |
"" |
Restore latest backup:
mariadb-backup-s3 restore \
--storage-url="s3://bucket/path" \
--target-dir=/var/lib/mysql \
--latest
Restore by filename or ID:
mariadb-backup-s3 restore --storage-url="s3://bucket/path" \
--target-dir=/tmp/restore \
2026-07-03-12-00-00.tar.gz
mariadb-backup-s3 restore --storage-url="s3://bucket/path" \
--target-dir=/tmp/restore \
2026-07-03-12-00-00.tar.gz.enc # .enc suffix for encrypted backups
mariadb-backup-s3 restore --storage-url="s3://bucket/path" \
--target-dir=/tmp/restore \
--backup-id="2026-07-03-12-00-00-a1b2c3d4"
Note
Logical backups (mariadb-dump) restore by extracting .sql files from the archive. Import them manually:
mariadb-backup-s3 restore --storage-url="s3://bucket/path" --target-dir=/tmp/restore --latest
mariadb -u root -p < /tmp/restore/mydb.sql
(back to top)
Retention
Apply retention policies to prune old backups.
mariadb-backup-s3 retention [options]
Options:
| Option |
Env Var |
Description |
Default |
--storage-url |
STORAGE__URL |
Storage URL |
required |
--retention-count |
RETENTION__COUNT |
Number of backups to retain |
0 |
--max-age |
RETENTION__MAX_AGE |
Maximum age (e.g. 24h, 168h) |
unlimited |
--keep-daily |
RETENTION__KEEP_DAILY |
Keep N per day |
0 (disabled) |
--keep-weekly |
RETENTION__KEEP_WEEKLY |
Keep N per week |
0 (disabled) |
--keep-monthly |
RETENTION__KEEP_MONTHLY |
Keep N per month |
0 (disabled) |
--dry-run |
RETENTION__DRY_RUN |
Preview without deleting |
false |
--force |
RETENTION__FORCE |
Continue despite errors |
false |
Examples:
# Keep only the 7 most recent backups
mariadb-backup-s3 retention \
--storage-url="s3://my-bucket/backups" \
--retention-count=7
# Keep backups from the last 7 days
mariadb-backup-s3 retention \
--storage-url="s3://my-bucket/backups" \
--max-age=168h
# Keep 1 daily for 7 days, 1 weekly for 4 weeks, 1 monthly for 12 months
mariadb-backup-s3 retention \
--storage-url="s3://my-bucket/backups" \
--keep-daily=7 \
--keep-weekly=4 \
--keep-monthly=12
# Preview what would be deleted
mariadb-backup-s3 retention \
--storage-url="s3://my-bucket/backups" \
--retention-count=3 \
--dry-run
Note
At least one retention policy must be enabled. The retention command will fail if no policies are specified.
(back to top)
Registry
View and manage the backup registry.
mariadb-backup-s3 registry list [options]
| Option |
Env Var |
Description |
Default |
--storage-url |
STORAGE__URL |
Storage URL |
required |
--rebuild |
|
Rebuild the registry from stored backups if it is missing |
false |
mariadb-backup-s3 registry list \
--storage-url="s3://my-bucket/backups"
Registry entry fields:
| Field |
Description |
id |
Unique identifier (timestamp + SHA256 prefix) |
filename |
Backup filename |
created_at |
Creation timestamp |
size_bytes |
File size in bytes |
sha256 |
SHA256 hash of the backup file |
status |
ready, failed, or deleted |
encrypted |
Whether the backup is encrypted |
encryption |
Encryption metadata (algorithm) |
tool.name, tool.version |
Tool name and version |
tool.method |
Backup method: mariadb-backup or mariadb-dump |
Note
Entries rebuilt with --rebuild use timestamp-only IDs, set sha256 to "unknown", and have an empty tool.method.
(back to top)
Scheduler
Built-in cron daemon that executes backup and retention jobs on a schedule without external cron or systemd timers.
mariadb-backup-s3 scheduler <command> [options]
Subcommands:
| Command |
Description |
run |
Start the scheduler daemon |
status |
Show the status of scheduled jobs |
check |
Validate a scheduler YAML config file |
Options:
| Option |
Env Var |
Description |
Default |
--config |
SCHEDULER__CONFIG |
Path to scheduler YAML config |
required |
--state-file |
SCHEDULER__STATE_FILE |
Path to persistent state file |
from config |
--once |
|
Run all enabled jobs once then exit |
false |
Example scheduler config:
# scheduler.yaml
state_file: /var/lib/mariadb-backup-s3/state.json
jobs:
- name: nightly-full-backup
schedule: "0 2 * * *"
command: backup
timeout: 4h
storage:
url: s3://my-bucket/backups?endpoint=https://s3.custom.com
mariadb:
host: localhost
port: 3306
user: root
password: ${MARIADB__PASSWORD}
backup_method: mariadb-backup
retention:
max_count: 7
# Validate the config
mariadb-backup-s3 scheduler check --config scheduler.yaml
# Run the scheduler daemon
mariadb-backup-s3 scheduler run --config scheduler.yaml
# Run all enabled jobs once and exit
mariadb-backup-s3 scheduler run --config scheduler.yaml --once
# Check job status
mariadb-backup-s3 scheduler status --config scheduler.yaml --state-file /var/lib/mariadb-backup-s3/state.json
Note
See examples/scheduler for a complete setup guide.
(back to top)
Storage Types
S3 Storage
For S3-compatible storage (AWS S3, MinIO, DigitalOcean Spaces, etc.):
STORAGE__URL=s3://bucket-name/path?endpoint=https://s3.example.com
Required environment variables:
| Env Var |
Description |
AWS_REGION |
AWS region |
AWS_ACCESS_KEY_ID |
Access key |
AWS_SECRET_ACCESS_KEY |
Secret key |
Query parameters:
| Parameter |
Description |
endpoint |
S3 endpoint URL |
s3-force-path-style |
Set to true to use path-style URLs |
part-size |
Multipart upload part size in bytes (default: 10485760 = 10 MB, min: 5242880 = 5 MB) |
FTP Storage
STORAGE__URL=ftp://username:password@host:port/path
Username defaults to anonymous.
Filesystem Storage
STORAGE__URL=file:///absolute/path/to/backup/directory
Examples:
- Linux/macOS:
file:///var/backups/mariadb
- Windows:
file:///C:/backups/mariadb
- Docker volume:
file:///data/backups
(back to top)
Encryption
Client-side encryption using AES-256-GCM for confidentiality and integrity verification.
Features:
- 256-bit key strength
- Authenticated encryption with associated data (AEAD)
- Automatic nonce generation per backup
- HKDF-SHA256 key derivation
Configuration:
# base64-encoded encryption key
# Replace with a unique value generated by: openssl rand -base64 32
ENCRYPTION__KEY=REPLACE_WITH_A_UNIQUE_BASE64_KEY
Key generation:
# Generate a 32-byte (256-bit) key
openssl rand -base64 32
# Alternative
head -c 32 /dev/urandom | base64
Security considerations:
- Never commit encryption keys to version control
- Store keys in secure environment variables or dedicated secret management systems
- Implement proper access controls for key storage
(back to top)
Examples
(back to top)
Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/amazing-feature)
- Commit your Changes (
git commit -m 'Add amazing feature')
- Push to the Branch (
git push origin feature/amazing-feature)
- Open a Pull Request
See CONTRIBUTORS.md for a list of contributors.
(back to top)
License
Distributed under the Apache 2.0 License. See LICENSE for details.
(back to top)
Project Link: https://github.com/capcom6/mariadb-backup-s3
(back to top)
Acknowledgments
(back to top)