Em qualquer PME com serviços Linux há sempre uma base de dados MariaDB ou MySQL a fazer subir algo crítico: o GLPI, o WordPress, a aplicação de faturação. Em regra, nunca teve um plano de backup. O que existe é um mysqldump solto num cron, muitas vezes sem consistência e nunca testado. Este artigo estrutura o sistema completo com as ferramentas nativas do MariaDB: dumps lógicos, backup físico com incrementos e recuperação a um ponto no tempo.
⚠ Antes de produção: implementa e testa este sistema primeiro num servidor de testes — replica as versões do MariaDB, o volume de dados e a carga de escrita do servidor real. Só depois de validares o restauro completo num ambiente de testes é que o plano deve chegar às máquinas de produção.
Neste artigo
Os três caminhos de backup
O MariaDB suporta três abordagens complementares:
- Lógico com
mariadb-dump(o antigomysqldump): gera SQL que recria as tabelas e os dados. Portável entre versões e fácil de inspecionar, mas lento em bases grandes e sem recuperação granular no tempo. - Físico com
mariadb-backup: copia os ficheiros do diretório de dados (InnoDB) num formato que restaura rapidamente. Suporta backups incrementais e é a base da recuperação a um ponto no tempo. - Paralelo com
mydumper: dump lógico multi-thread, ordenado por tabela — útil para bases com dezenas de GB onde o dump sequencial demora horas.
A combinação típica de PME: full físico semanal + incrementos diários + binary logs para PITR, com um dump lógico semanal como seguro de portabilidade.
Camadas diferentes: o backup físico copia os ficheiros da base de dados, não o sistema inteiro — por isso convive bem com um backup de imagem/disk-level do servidor (restic, snapshots), que cobre o resto da máquina.
mariadb-dump: o dump lógico consistente
Utilizador de backup
CREATE USER 'backup'@'localhost' IDENTIFIED BY 'senha_longa';
GRANT SELECT, SHOW VIEW, EVENT, TRIGGER, LOCK TABLES, RELOAD, BINLOG MONITOR
ON *.* TO 'backup'@'localhost';
O EVENT é preciso para o –events entrar no dump, e o RELOAD é preciso porque o –master-data com –single-transaction toma um read lock global curto no início do dump (a documentação da MariaDB nota que com –single-transaction o lock global é só breve, mas é tomado). Os nomes BINLOG MONITOR e os binários mariadb-* existem desde a MariaDB 10.5 — em versões anteriores o privilégio é REPLICATION CLIENT e os binários chamam-se mysql*.
Dump online e consistente
O erro clássico do mysqldump em cron é bloquear a aplicação com --lock-tables ou produzir um dump inconsistente em InnoDB. O correto em servidores em produção é uma transação com snapshot consistente:
mariadb-dump --single-transaction \
--routines --events --triggers \
--master-data=2 \
-u backup -p --all-databases \
| gzip > /var/backups/mariadb/full-$(date +%F).sql.gz
O --single-transaction faz um START TRANSACTION com snapshot consistente: sem bloquear aplicações, o dump captura o estado de todas as tabelas InnoDB ao momento do BEGIN. Só é válido para tabelas transacionais: tabelas MyISAM à mistura ficam inconsistentes. O --routines --events evita a perda silenciosa de procedimentos e eventos — só estes dois não entram no dump por omissão. Os triggers entram sempre — o --triggers explícito não faz mal, mas não é ele que evita perdas. Com --master-data=2, o dump grava ainda a coordenada do binary log num comentário, o ponto de partida da recuperação a um ponto no tempo.
Cuidado: durante um dump com --single-transaction, evita DDL e DML destrutivo em produção (ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE) — um schema change ou um truncate durante o dump quebra a consistência do snapshot.
Restauro
gunzip < full-2026-10-10.sql.gz | mariadb -u root -p
mariadb-backup: backup físico com incrementos
O mariadb-backup (herdeiro do XtraBackup) copia os ficheiros InnoDB enquanto o servidor escreve, gravando o redo log registado durante a cópia para tornar o backup restaurável. É rápido de restaurar porque não recompila índices nem interpreta SQL — só repõe os ficheiros.
O utilizador precisa destes privilégios: RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR.
Full backup
mariadb-backup --backup \
--target-dir=/var/backups/mariadb/full \
--user=backup -p
O diretório de destino tem de estar vazio (ou nem existir). Ao terminar, o ficheiro xtrabackup_binlog_info dentro dele grava o nome e a posição do binary log no momento do backup — a coordenada que alimenta o PITR.
Prepare
Um backup cru não é consistente: os ficheiros foram copiados a momentos ligeiramente diferentes. Antes de restaurar (ou de aplicar incrementos), prepara-se:
mariadb-backup --prepare \
--target-dir=/var/backups/mariadb/full
Incrementos diários
Com --incremental-basedir sempre apontado ao full, cada incremento é um delta face ao full (diferencial): grava as páginas InnoDB alteradas desde o full, por LSN (log sequence number). É por isso que só o último incremento interessa no restauro:
mariadb-backup --backup \
--target-dir=/var/backups/mariadb/inc-$(date +%F) \
--incremental-basedir=/var/backups/mariadb/full \
--user=backup -p
No restauro, o –prepare faz-se só nessa altura, sobre a cópia gravada em disco — preparar a base antes de tirar os incrementos altera-a e estraga a cadeia. Depois, aplica-se o último incremento ao base (os anteriores já estão contidos nele, porque todos apontam para o mesmo full):
mariadb-backup --prepare --target-dir=/var/backups/mariadb/full
mariadb-backup --prepare --target-dir=/var/backups/mariadb/full \
--incremental-dir=/var/backups/mariadb/inc-2026-10-10
Restauro
systemctl stop mariadb
rm -rf /var/lib/mysql/* # o datadir tem de ficar vazio
mariadb-backup --copy-back \
--target-dir=/var/backups/mariadb/full
chown -R mysql:mysql /var/lib/mysql
systemctl start mariadb
O --copy-back preserva os ficheiros originais do backup — o --move-back os move (o backup deixa de estar no diretório de origem). Não esquecer o chown: os ficheiros são escritos como o utilizador que corre o restore, e o mariadbd recusa um datadir com dono errado.
PITR: recuperação a um ponto no tempo
O backup restaura o directório de dados à hora da cópia, mas um DROP TABLE às 15h não existe no backup das 02h. A recuperação a um ponto no tempo repõe o efeito do binary log a seguir ao restauro — mas só funciona se o binary logging estiver activo, porque vem desligado por omissão.
Duas preparações obrigatórias, antes de precisares disto:
- Activar o binary log —
log_binno my.cnf (a documentação da MariaDB mostramariadbd --log-bin=/var/log/mariadb/mariadb-logs). Sem basename, os ficheiros ficam no datadir — com um nome derivado do hostname ou UUID. - Guardar os binlogs fora do datadir. Por omissão vivem no datadir — e o restauro físico começa por esvaziar esse directório. Copia os ficheiros do binlog para /var/backups/mariadb/binlogs antes de apagar, ou configura um caminho próprio no –log-bin.
No restauro, o ponto de partida vem do ficheiro xtrabackup_binlog_info dentro do backup preparado — ele indica o ficheiro de binlog e a posição exacta em que o backup parou (a documentação da MariaDB usa 321 como exemplo). A partir desse ficheiro e posição, aplica-se todos os binlogs posteriores com mariadb-binlog, por ordem, até à hora do desastre:
mariadb-binlog --start-position=321 \
--stop-datetime="2026-10-10 14:59:59" \
/var/backups/mariadb/binlogs/mariadb-bin.000012 \
/var/backups/mariadb/binlogs/mariadb-bin.000013 \
> /tmp/pitr.sql
mariadb -u root -p < /tmp/pitr.sql
O --stop-datetime é a segunda antes do desastre: os eventos posteriores ficam de fora. Se o desastre foi nos últimos minutos e o servidor continuou a gravar, o ficheiro corrente também entra na lista — o mariadb-binlog processa a lista toda numa passagem, mantendo a ordem. E atenção à retenção: os binlogs antigos são purgados pelo servidor com binlog_expire_logs_seconds, e se desaparecerem antes do backup mais antigo que precisas de recombinar, o buraco na cadeia fica sem cura. A cópia para fora do host resolve.
mydumper: dump lógico paralelo
O mydumper exporta em múltiplas threads, com snapshot consistente partilhado entre elas, e escreve um ficheiro por tabela — fácil de restaurar parcialmente. O par myloader importa. Para uma base de 50 GB em que o mariadb-dump leva horas, é a diferença entre viável e inviável.
mydumper --ask-password -u backup -h 127.0.0.1 \
-o /var/backups/mariadb/dump-$(date +%F) \
--compress --threads 4
myloader --ask-password -u root -d /var/backups/mariadb/dump-2026-10-10 \
--threads 4
O -p do mydumper e do myloader exige a password como argumento — chamado sem valor, ele engole a opção seguinte como password (o -h 127.0.0.1 seria comido). O --ask-password pergunta em prompt e evita passwords em comandos e logs. E em cron a alternativa é um --defaults-file só de leitura pela conta de backup.
Automatizar
Esqueleto de cron para o ciclo semanal:
# /etc/cron.d/mariadb-backups
# full físico domingo 01:00
0 1 * * 0 root /usr/local/bin/mariadb-full.sh
# incremento diário 03:30 (depois do full de domingo às 01:00)
30 3 * * * root /usr/local/bin/mariadb-inc.sh
# dump lógico segunda 02:00
0 2 * * 1 root /usr/local/bin/mariadb-dump-weekly.sh
Para o armazenamento: os diretórios de backup vivem no servidor de BD por conveniência, mas têm de ser copiados para fora do host (armazenamento remoto, segundo servidor). A nota do horário não é cosmética: com o incremento às 00:30 de domingo e o full às 01:00, o incremento de domingo calculava o delta contra o full da semana anterior — a janela de nove dias antecede qualquer desastre. Um backup dentro do único disco da base de dados dá falsa segurança, não é um backup.
Validar o restauro (o passo que salta)
Um backup não verificado é uma suposição. O mínimo aceitável numa PME é repetir uma vez por mês:
- Restaurar o último backup num servidor de teste (VM, container ou máquina do técnico).
- Verificar que o
mariadbdarranca sem erros no log. - Entrar na base e contar as linhas das tabelas críticas, comparando com produção.
- Se a aplicação permitir, apontar uma instância de teste dela ao servidor de teste — a base arrancar não significa que os dados façam sentido.