Menu
Szybki wybór
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

MySQL backup — automatyzacja i rotacja kopii zapasowych

Opublikowano: 9 kwietnia 2026 · Kategoria: Bazy danych

Backup bazy danych to nie jednorazowe zadanie — to proces, który musi działać automatycznie, być weryfikowany i przechowywany poza serwerem głównym. Ten artykuł pokazuje jak zbudować kompletny system backupu MySQL: od mysqldump przez rotację, upload do S3/Backblaze B2, po monitoring i testowanie przywracania.

mysqldump — podstawy i ważne opcje

mysqldump to standardowe narzędzie do tworzenia logicznych kopii baz MySQL/MariaDB. Generuje plik SQL z instrukcjami CREATE TABLE i INSERT, który można przywrócić na dowolnym serwerze z kompatybilną wersją MySQL.

# Backup jednej bazy danych (InnoDB — bez blokowania tabel)
mysqldump \
  --single-transaction \
  --quick \
  --lock-tables=false \
  -u root -p nazwa_bazy > /backup/nazwa_bazy.sql

# Backup wszystkich baz danych
mysqldump \
  --single-transaction \
  --all-databases \
  --events \
  --routines \
  --triggers \
  -u root -p > /backup/all_databases.sql

# Backup z natychmiastową kompresją (pipe do gzip)
mysqldump --single-transaction -u root -p nazwa_bazy | gzip > /backup/nazwa_bazy.sql.gz

# Przywracanie z pliku SQL
mysql -u root -p nazwa_bazy < /backup/nazwa_bazy.sql

# Przywracanie z archiwum gzip
gunzip < /backup/nazwa_bazy.sql.gz | mysql -u root -p nazwa_bazy

Tip: Utwórz dedykowanego użytkownika MySQL tylko do backupów z minimalnymi uprawnieniami: GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost' IDENTIFIED BY 'haslo'; — przechowuj dane logowania w pliku ~/.my.cnf aby uniknąć hasła w skrypcie.

Skrypt backup z rotacją 7/4/12

Standardowa strategia rotacji to: 7 backupów dziennych, 4 tygodniowe, 12 miesięcznych. Poniższy skrypt implementuje tę strategię w Bashu:

#!/bin/bash
# /usr/local/bin/mysql-backup.sh
# Backup MySQL z rotacją 7/4/12 i powiadomieniem email

set -euo pipefail

# --- KONFIGURACJA ---
DB_USER="backup_user"
DB_PASS="twoje_haslo"
BACKUP_DIR="/backup/mysql"
LOG_FILE="/var/log/mysql-backup.log"
ALERT_EMAIL="[email protected]"
KEEP_DAILY=7
KEEP_WEEKLY=4
KEEP_MONTHLY=12

# --- FUNKCJE ---
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}

alert() {
    echo "$1" | mail -s "BACKUP ERROR: MySQL backup failed" "$ALERT_EMAIL"
}

# --- GŁÓWNA LOGIKA ---
TODAY=$(date +%Y-%m-%d)
DAY_OF_WEEK=$(date +%u)   # 1=Pon, 7=Nie
DAY_OF_MONTH=$(date +%d)

mkdir -p "$BACKUP_DIR"/{daily,weekly,monthly}

log "Starting MySQL backup..."

# Lista baz danych (pomiń systemowe)
DATABASES=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW DATABASES;" 2>/dev/null | \
    grep -Ev "(Database|information_schema|performance_schema|sys)")

# Backup każdej bazy
for DB in $DATABASES; do
    FILENAME="${DB}_${TODAY}.sql.gz"

    log "Dumping: $DB"
    mysqldump \
        --single-transaction \
        --quick \
        --lock-tables=false \
        -u"$DB_USER" -p"$DB_PASS" \
        "$DB" 2>/dev/null | gzip > "$BACKUP_DIR/daily/$FILENAME"

    # Tygodniowy (każda niedziela)
    if [ "$DAY_OF_WEEK" -eq 7 ]; then
        cp "$BACKUP_DIR/daily/$FILENAME" "$BACKUP_DIR/weekly/$FILENAME"
        log "Weekly backup saved: $FILENAME"
    fi

    # Miesięczny (1. dzień miesiąca)
    if [ "$DAY_OF_MONTH" -eq "01" ]; then
        cp "$BACKUP_DIR/daily/$FILENAME" "$BACKUP_DIR/monthly/$FILENAME"
        log "Monthly backup saved: $FILENAME"
    fi
done

# Rotacja: usuń stare backupy
find "$BACKUP_DIR/daily"   -name "*.sql.gz" -mtime +"$KEEP_DAILY"   -delete
find "$BACKUP_DIR/weekly"  -name "*.sql.gz" -mtime +$(( KEEP_WEEKLY * 7 ))  -delete
find "$BACKUP_DIR/monthly" -name "*.sql.gz" -mtime +$(( KEEP_MONTHLY * 31 )) -delete

log "Backup completed. Disk usage: $(du -sh $BACKUP_DIR | cut -f1)"
# Nadaj uprawnienia i dodaj do crona
sudo chmod +x /usr/local/bin/mysql-backup.sh

# Cron: backup codziennie o 2:00 w nocy
crontab -e
# Dodaj:
0 2 * * * /usr/local/bin/mysql-backup.sh >> /var/log/mysql-backup.log 2>&1

Backup na zewnętrzne storage — rclone + S3/Backblaze B2

Backup przechowywany tylko na serwerze głównym nie jest prawdziwym backupem — awaria dysku niszczy i dane, i kopię. Użyj rclone do automatycznego uploadu na zewnętrzne storage:

# Instalacja rclone
curl https://rclone.org/install.sh | sudo bash

# Konfiguracja (interaktywna)
rclone config
# Wybierz: n (nowy remote)
# Nazwa: backblaze-b2
# Typ: b2 (Backblaze B2)
# Podaj: account ID, application key
# Bucket: twoj-bucket-backup

# Test połączenia
rclone lsd backblaze-b2:twoj-bucket-backup

# Upload katalogu backup
rclone sync /backup/mysql backblaze-b2:twoj-bucket-backup/mysql \
    --transfers 4 \
    --log-level INFO \
    --log-file /var/log/rclone-backup.log
# Dodaj rclone sync do skryptu backup (po rotacji lokalnej)
# W mysql-backup.sh:

log "Uploading to Backblaze B2..."
rclone sync "$BACKUP_DIR" backblaze-b2:twoj-bucket-backup/mysql \
    --transfers 4 \
    --quiet \
    --log-file "$LOG_FILE" || alert "rclone upload failed!"

log "Upload complete."
Storage Cena/GB/mies. Egress Uwagi
AWS S3 ~$0.023 $0.09/GB Najdroższy, best-in-class niezawodność, najszersza integracja
Backblaze B2 ~$0.006 Darmowy do Cloudflare Najtańszy, rclone-native, idealny dla backupów
Wasabi ~$0.0068 Darmowy Min. 90 dni przechowywania per obiekt — uwaga przy częstych nadpisaniach

Percona XtraBackup — hot backup bez locka

Dla baz danych powyżej kilku GB, gdzie mysqldump trwa zbyt długo, Percona XtraBackup oferuje fizyczne kopie plików InnoDB bez blokowania tabel:

# Instalacja Percona XtraBackup (Ubuntu 22.04)
wget https://downloads.percona.com/downloads/Percona-XtraBackup-8.0/latest/binary/debian/jammy/x86_64/percona-xtrabackup-80_8.0.36-31-1.jammy_amd64.deb
sudo dpkg -i percona-xtrabackup-80_*.deb

# Pełny backup
xtrabackup \
    --backup \
    --target-dir=/backup/xtrabackup/full \
    --user=root \
    --password=twoje_haslo

# Incremental backup (tylko zmiany od ostatniego backupu)
xtrabackup \
    --backup \
    --incremental-basedir=/backup/xtrabackup/full \
    --target-dir=/backup/xtrabackup/inc1 \
    --user=root \
    --password=twoje_haslo

# Przygotowanie do przywracania (prepare)
xtrabackup --prepare --target-dir=/backup/xtrabackup/full

# Przywracanie (MySQL musi być zatrzymany!)
sudo systemctl stop mysql
xtrabackup --copy-back --target-dir=/backup/xtrabackup/full
sudo chown -R mysql:mysql /var/lib/mysql
sudo systemctl start mysql

Testowanie restore — obowiązkowe

Backup bez testu przywracania nie jest wiarygodny. Zautomatyzuj test restore raz w tygodniu:

#!/bin/bash
# /usr/local/bin/test-mysql-restore.sh

BACKUP_FILE=$(ls -t /backup/mysql/daily/nazwa_bazy_*.sql.gz | head -1)
TEST_DB="restore_test_${RANDOM}"

echo "Testing restore: $BACKUP_FILE"

# Utwórz testową bazę
mysql -u root -p -e "CREATE DATABASE $TEST_DB;"

# Przywróć backup
gunzip < "$BACKUP_FILE" | mysql -u root -p "$TEST_DB"

# Weryfikuj tabele
TABLE_COUNT=$(mysql -u root -p -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$TEST_DB';" -sN)
echo "Tables restored: $TABLE_COUNT"

# Usuń bazę testową
mysql -u root -p -e "DROP DATABASE $TEST_DB;"

echo "Restore test: PASSED ($TABLE_COUNT tables)"

Najczęstsze pytania

Dlaczego mysqldump wymaga --single-transaction dla InnoDB? +
Opcja --single-transaction uruchamia zrzut bazy w ramach jednej transakcji REPEATABLE READ. Dzięki temu mysqldump widzi spójny snapshot danych z momentu rozpoczęcia backupu, bez blokowania tabel przez cały czas trwania operacji. Bez tej opcji mysqldump używa LOCK TABLES, co blokuje zapisy do bazy przez cały czas trwania backupu — problematyczne dla produkcyjnych baz z dużym ruchem. Opcja --single-transaction działa TYLKO z silnikiem InnoDB; dla MyISAM nadal potrzebny jest LOCK TABLES.
Jak szybko można przywrócić bazę z mysqldump? +
Czas przywracania zależy od rozmiaru bazy. Dla bazy 1 GB: mysql -u root -p nazwa_bazy < backup.sql typowo trwa 2-5 minut. Dla baz 10-100 GB może trwać godziny — dlatego dla dużych baz warto rozważyć Percona XtraBackup, który tworzy binarne kopie plików InnoDB i przywraca je znacznie szybciej (minuty zamiast godzin). Przed przywróceniem zawsze testuj backup na oddzielnym serwerze i weryfikuj integralność: mysqlcheck -u root -p --all-databases po przywróceniu.
Jak wybrać między S3, Backblaze B2 a Wasabi do przechowywania backupów? +
AWS S3: najdroższy (~$0.023/GB/mies), ale najbardziej niezawodny z najszerszą integracją. Backblaze B2: najtańszy (~$0.006/GB/mies), darmowy egress do Cloudflare, idealny dla backupów które rzadko pobierasz. Wasabi: ~$0.0068/GB/mies, brak opłat za egress (ale minimum 90 dni przechowywania per obiekt). Dla backupów MySQL rekomendacja: Backblaze B2 za cenę i prostotę, lub Wasabi jeśli backupy są rzadko pobierane ale regularnie nadpisywane.
Czym różni się Percona XtraBackup od mysqldump? +
mysqldump tworzy tekstowy plik SQL z instrukcjami INSERT — przywracanie wymaga ponownego wykonania każdego zapytania, co jest wolne dla dużych baz. Percona XtraBackup kopiuje binarne pliki InnoDB bezpośrednio z dysku (hot backup — bez blokowania), a przywracanie to szybkie kopiowanie plików. XtraBackup obsługuje też incremental backup (tylko zmiany od ostatniego backupu) i backup streaming do S3. Wada: większy plik backupu (brak kompresji SQL), wymagana ta sama lub kompatybilna wersja MySQL/Percona przy przywracaniu.

Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.