dbbackup

A CLI tool for backing up MySQL databases to cloud storage. Supports Cloudflare R2 and AWS S3 (or any S3-compatible service) as storage backends.
Features
- MySQL backup via pure Go library (no external dependencies) or
mysqldump binary
- Cloudflare R2 and AWS S3 storage (including S3-compatible services like MinIO)
- Gzip compression (optional)
- Retention policies — keep N latest backups or delete older than X days
- Notifications — Telegram, Slack, and generic webhook
- TOML configuration with CLI flag overrides
- Extensible architecture — easy to add new DB engines, storage backends, or notification channels
Installation
Quick install (Linux/macOS)
curl -sSL https://raw.githubusercontent.com/thanhtaivtt/dbbackup/main/install.sh | sh
From releases
Download the latest binary from the Releases page.
From source
go install github.com/thanhtaivtt/dbbackup@latest
Build locally
make build
Usage
# Generate config file
dbbackup init
# Edit config
vim config.toml
# Run backup
dbbackup backup --config config.toml
# With CLI overrides
dbbackup backup --config config.toml --compress --retention-count 5
# Verbose output
dbbackup backup --config config.toml -v
Cron setup (daily at 2AM)
0 2 * * * /usr/local/bin/dbbackup backup --config /etc/dbbackup/config.toml
Configuration
See config.example.toml for a full example.
[backup]
| Key |
Type |
Default |
Description |
compress |
bool |
false |
Enable gzip compression for backup files |
dump_method |
string |
"go" |
MySQL dump method: "go" (pure Go library, supports remote DB) or "binary" (requires mysqldump CLI installed on host) |
[database.mysql]
| Key |
Type |
Default |
Description |
host |
string |
"localhost" |
MySQL server hostname or IP |
port |
int |
3306 |
MySQL server port |
user |
string |
required |
MySQL user |
password |
string |
required |
MySQL password |
databases |
[]string |
required |
List of database names to back up |
[storage]
| Key |
Type |
Default |
Description |
backend |
string |
"r2" |
Storage backend: "r2" (Cloudflare R2) or "s3" (AWS S3 / S3-compatible) |
[storage.r2]
| Key |
Type |
Default |
Description |
account_id |
string |
required |
Cloudflare account ID |
access_key_id |
string |
required |
R2 API token Access Key ID |
access_key_secret |
string |
required |
R2 API token Secret Access Key |
bucket |
string |
required |
R2 bucket name |
path_prefix |
string |
"" |
Prefix for object keys (e.g. "mysql/" → mysql/mydb_20240101_020000.sql.gz) |
[storage.s3]
| Key |
Type |
Default |
Description |
region |
string |
required |
AWS region (e.g. "ap-southeast-1") |
access_key_id |
string |
optional |
AWS Access Key ID (falls back to default credentials) |
secret_access_key |
string |
optional |
AWS Secret Access Key |
bucket |
string |
required |
S3 bucket name |
path_prefix |
string |
"" |
Prefix for object keys |
endpoint |
string |
"" |
Custom endpoint for S3-compatible services (MinIO, etc.) |
[retention]
| Key |
Type |
Default |
Description |
strategy |
string |
"count" |
Retention strategy: "count" (keep N latest) or "days" (keep for N days) |
count |
int |
7 |
Number of backups to keep (when strategy = "count") |
days |
int |
30 |
Days to keep backups (when strategy = "days") |
[notification.telegram]
| Key |
Type |
Default |
Description |
enabled |
bool |
false |
Enable Telegram notifications |
bot_token |
string |
required |
Telegram Bot API token (from @BotFather) |
chat_id |
string |
required |
Target chat/group ID (use @userinfobot to find) |
[notification.slack]
| Key |
Type |
Default |
Description |
enabled |
bool |
false |
Enable Slack notifications |
webhook_url |
string |
required |
Slack Incoming Webhook URL |
[notification.webhook]
| Key |
Type |
Default |
Description |
enabled |
bool |
false |
Enable generic webhook notifications |
url |
string |
required |
Webhook endpoint URL (receives JSON POST) |
Minimal config example
[database.mysql]
user = "root"
password = "secret"
databases = ["mydb"]
[storage.r2]
account_id = "your-account-id"
access_key_id = "your-access-key-id"
access_key_secret = "your-access-key-secret"
bucket = "db-backups"
Full config example
[backup]
compress = true
dump_method = "go"
[database.mysql]
host = "localhost"
port = 3306
user = "root"
password = "secret"
databases = ["mydb", "analytics"]
[storage.r2]
account_id = "your-account-id"
access_key_id = "your-access-key-id"
access_key_secret = "your-access-key-secret"
bucket = "db-backups"
path_prefix = "mysql/"
[retention]
strategy = "count"
count = 7
[notification.telegram]
enabled = true
bot_token = "123456:ABC-DEF"
chat_id = "-1001234567890"
[notification.slack]
enabled = false
webhook_url = "https://hooks.slack.com/services/T.../B.../xxx"
[notification.webhook]
enabled = false
url = "https://your-server.com/webhook/backup"
CLI Flags
| Flag |
Description |
--config |
Config file path (default: config.toml) |
--compress |
Enable gzip compression |
--retention-count N |
Keep N latest backups |
--retention-days N |
Keep backups for N days |
-v, --verbose |
Enable debug logging |
--version |
Print version info |
Commands
| Command |
Description |
init |
Generate a config file |
backup |
Run database backup |
update |
Check for new version on GitHub |
Extending
Add a new database
Implement the Dumper interface in internal/dumper/:
type Dumper interface {
Dump(ctx context.Context, database string) (io.ReadCloser, error)
Name() string
}
Add a new storage backend
Implement the Storage interface in internal/storage/:
type Storage interface {
Upload(ctx context.Context, key string, reader io.Reader) error
List(ctx context.Context, prefix string) ([]Object, error)
Delete(ctx context.Context, keys []string) error
Name() string
}
Add a new notification channel
Implement the Notifier interface in internal/notifier/:
type Notifier interface {
Notify(ctx context.Context, msg Message) error
Name() string
}
License
MIT — see LICENSE.