Aula 21: Backup — pg_dump, pg_basebackup e Point-in-Time Recovery
Nenhuma estratégia de administração de banco de dados pode ser considerada séria sem um plano de backup robusto, testado e automatizado. Nesta aula avançada do curso PostgreSQL — Do Zero ao Avançado, você vai dominar as três ferramentas nativas mais importantes para proteger dados no PostgreSQL: o pg_dump, responsável por backups lógicos; o pg_basebackup, que gera backups físicos completos do cluster; e o mecanismo de Point-in-Time Recovery (PITR), que combina um backup físico base com o arquivamento contínuo de WAL para permitir restaurações até um momento exato no tempo. O objetivo é transformar você de alguém que “faz cópias” em um profissional que projeta e executa estratégias de recuperação de desastres com segurança e previsibilidade.
O PostgreSQL oferece um ecossistema de backup extremamente flexível, mas também repleto de detalhes que, se ignorados, levam a backups inúteis ou restaurações falhas. Um backup lógico com pg_dump é perfeito para extrair schemas, migrar bases entre versões ou realizar backups seletivos de tabelas, mas ele não captura o estado físico do cluster nem permite recuperação até um ponto arbitrário no tempo. Já o pg_basebackup, associado ao arquivamento de WAL, é a base do PITR e da replicação física, permitindo reconstruir um ambiente completo ou criar réplicas standby. Entender quando usar cada ferramenta e como combiná-las é o que separa um DBA júnior de um profissional avançado.
Por que isso importa? Porque em ambientes de produção, uma falha de hardware, um erro humano de DELETE sem WHERE ou uma corrupção de arquivos pode significar a perda irreversível de horas, dias ou até meses de dados. Sem um backup válido, não há restauração possível. Com as técnicas desta aula, você será capaz de recuperar desde um único objeto até um cluster inteiro, reduzindo o RPO (Recovery Point Objective) e o RTO (Recovery Time Objective) a patamares aceitáveis para a maioria das aplicações críticas. Em nossos projetos na JRT Technology Solutions, a validação de backups é uma etapa obrigatória antes de qualquer liberação para produção.
Para acompanhar esta aula, você precisará de um servidor Linux com o PostgreSQL 16 instalado e em execução, além de acesso ao usuário postgres ou a um superusuário equivalente. Recomendamos fortemente que você utilize uma máquina virtual ou container dedicado a testes, pois vamos parar e reiniciar o serviço, mover diretórios de dados e executar comandos destrutivos em um ambiente controlado. Os procedimentos foram validados em Ubuntu/Debian e em CentOS/RHEL/Rocky Linux, cobrindo as diferenças de diretórios e gerenciamento de serviços dessas famílias.
Ao final desta aula, você será capaz de: criar backups lógicos em todos os formatos suportados pelo pg_dump; gerar backups físicos completos e consistentes com pg_basebackup; configurar o arquivamento automático de WAL; restaurar um cluster inteiro a partir de um backup físico; e executar recuperação Point-in-Time Recovery até um horário, uma transação ou um ponto de restauração previamente definido. Vamos começar pelos fundamentos que tornam tudo isso possível.
O que você vai aprender nesta aula
- Diferenciar backup lógico de backup físico e compreender o papel do WAL na recuperação.
- Utilizar pg_dump e pg_dumpall para gerar scripts SQL e arquivos customizados de backup, com opções de filtragem, compressão e paralelismo.
- Configurar o servidor para aceitar conexões de replicação e executar pg_basebackup para obter uma cópia física consistente do cluster.
- Ativar e validar o arquivamento contínuo de WAL com
archive_modeearchive_command. - Realizar restaurações completas e recuperação Point-in-Time Recovery (PITR) configurando
restore_commanderecovery_target_*. - Verificar a integridade dos seus backups com pg_verifybackup e interpretar saídas de logs de recuperação.
- Aplicar boas práticas de retenção, automatização, monitoramento e testes periódicos de restauração.
Pré-requisitos e Ambiente
Antes de iniciar os procedimentos práticos, certifique-se de que o PostgreSQL 16 está instalado e funcional no seu servidor Linux. Se você seguiu as aulas anteriores do curso, já deve ter o cluster inicializado e em execução. Caso contrário, utilize os comandos abaixo para instalar os pacotes básicos no Ubuntu 22.04/Debian 12 e no Rocky Linux 9. Os exemplos foram testados com PostgreSQL 16, mas a maioria dos comandos é compatível com versões 12 ou superiores, desde que você ajuste os caminhos e nomes de serviço.
No Ubuntu/Debian, a instalação do servidor e dos utilitários de cliente pode ser feita com o repositório oficial da PostgreSQL Global Development Group. Execute:
# Ubuntu/Debian: instalar PostgreSQL 16 e utilitários de backup
sudo apt update
sudo apt install -y postgresql-16 postgresql-client-16
sudo systemctl enable --now postgresql
sudo systemctl status postgresql --no-pager
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; preset: enabled)
Active: active (exited) since Wed 2026-08-26 09:15:00 -03; 1h ago
Process: 2345 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
Main PID: 2345 (code=exited, status=0/SUCCESS)
CPU: 4ms
No Rocky Linux 9 / RHEL 9, você precisa habilitar o módulo correspondente e instalar o servidor e o cliente. Os comandos são:
# Rocky Linux / RHEL 9: instalar PostgreSQL 16 e utilitários de backup
sudo dnf install -y postgresql16-server postgresql16
sudo /usr/pgsql-16/bin/postgresql-16-setup initdb
sudo systemctl enable --now postgresql-16
sudo systemctl status postgresql-16 --no-pager
● postgresql-16.service - PostgreSQL 16 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-16.service; enabled; preset: disabled)
Active: active (running) since Wed 2026-08-26 09:20:00 -03; 1h ago
Main PID: 3120 (postgres)
Tasks: 8 (limit: 2313)
Memory: 28.9M
CGroup: /system.slice/postgresql-16.service
Além dos pacotes, você precisará de acesso ao usuário postgres ou a um papel com privilégios de SUPERUSER. Todos os comandos de backup e restauração que envolvem o sistema de arquivos exigem permissões adequadas nos diretórios de destino. Recomendamos criar um diretório exclusivo para os artefatos de backup, por exemplo /var/backups/postgresql no Ubuntu ou /var/lib/pgsql/backups no Rocky, e conceder permissão de escrita ao usuário postgres. Abaixo mostramos como preparar esse diretório nas duas famílias.
# Ubuntu/Debian: criar diretório de backups e ajustar permissões
sudo mkdir -p /var/backups/postgresql
sudo chown postgres:postgres /var/backups/postgresql
sudo -u postgres psql -c "SELECT version();"
version
--------------------------------------------------------------------------------------------------------------
PostgreSQL 16.0 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 12.2.0-14ubuntu2) 12.2.0, 64-bit
(1 row)
# Rocky Linux / RHEL 9: criar diretório de backups e ajustar permissões
sudo mkdir -p /var/lib/pgsql/backups
sudo chown postgres:postgres /var/lib/pgsql/backups
sudo -u postgres psql -c "SELECT version();"
version
--------------------------------------------------------------------------------------------------------------
PostgreSQL 16.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-2), 64-bit
(1 row)
Com o ambiente pronto, você também precisa ter um banco de dados de exemplo para testar os procedimentos. Vamos criar um banco chamado loja com algumas tabelas e dados. Esse banco será usado em todos os exemplos de backup e restauração desta aula. Conecte-se ao PostgreSQL com o usuário postgres e execute os comandos SQL abaixo.
# Criar banco de exemplo e popular tabelas
sudo -u postgres psql <<'EOF'
CREATE DATABASE loja;
\c loja
CREATE TABLE clientes (
id SERIAL PRIMARY KEY,
nome TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
criado_em TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE pedidos (
id SERIAL PRIMARY KEY,
cliente_id INT REFERENCES clientes(id),
valor NUMERIC(10,2) NOT NULL,
criado_em TIMESTAMPTZ DEFAULT now()
);
INSERT INTO clientes (nome, email) VALUES
('Ana Souza', 'ana@example.com'),
('Bruno Lima', 'bruno@example.com'),
('Carla Prado', 'carla@example.com');
INSERT INTO pedidos (cliente_id, valor) VALUES
(1, 199.90),
(2, 540.00),
(3, 87.35);
EOF
CREATE DATABASE
You are now connected to database "loja" as user "postgres".
CREATE TABLE
CREATE TABLE
INSERT 0 3
INSERT 0 3
Fundamentos: Backup Lógico vs Backup Físico e o Papel do WAL
Antes de executar qualquer ferramenta, é essencial compreender as duas categorias principais de backup no PostgreSQL. O backup lógico é aquele que extrai o conteúdo dos bancos em um formato compreensível pelo próprio PostgreSQL ou por outras ferramentas — normalmente comandos SQL ou um formato binário customizado. O pg_dump, o pg_dumpall e o COPY TO são exemplos de utilitários lógicos. Eles permitem recuperar objetos individuais, migrar entre versões, reordenar dados e até modificar o conteúdo antes da restauração. No entanto, um backup lógico não é uma imagem consistente do cluster como um todo; ele é uma fotografia lógica da base no momento em que a conexão foi estabelecida, dependendo de transações com isolamento REPEATABLE READ.
O backup físico, por outro lado, copia os arquivos binários que compõem o cluster — o diretório de dados, os tablespaces e, quando configurado, os arquivos de WAL. O pg_basebackup é a ferramenta nativa para esse tipo de cópia. Um backup físico é essencial para ambientes de grande volume, pois a restauração é muito mais rápida (não há recriação de índices via SQL) e pode ser combinada com o WAL arquivado para permitir recuperação até um ponto no tempo. Porém, o backup físico é específico da versão e da plataforma; você não pode, por exemplo, restaurar um backup físico do PostgreSQL 16 em um servidor Windows se o backup foi gerado em Linux.
O WAL (Write-Ahead Logging) é o mecanismo central que torna tudo isso possível. Antes de modificar qualquer página de dados, o PostgreSQL grava a mudança correspondente no WAL, garantindo durabilidade e permitindo recuperação após falhas. Esses registros são segmentados em arquivos de 16 MB (por padrão) armazenados no subdiretório pg_wal. Quando ativamos o archiving, o PostgreSQL envia cada segmento completado para um local externo por meio do comando definido em archive_command. Esse fluxo contínuo de WAL arquivado é o que permite reconstruir o estado do banco desde o último backup físico até qualquer instante posterior.
Para implementar um plano de backup completo, a estratégia padrão em produção combina um pg_basebackup periódico (por exemplo, diário ou semanal) com o arquivamento contínuo de WAL. Com isso, se ocorrer uma falha às 14h32, você restaura o backup físico das 02h00 e aplica todos os segmentos de WAL arquivados até as 14h31. Esse é o conceito de Point-in-Time Recovery: o cluster volta exatamente ao estado desejado, nem antes nem depois. Sem o arquivamento de WAL, o pg_basebackup sozinho permite apenas a restauração do instante em que o backup foi concluído, sem granularidade temporal.
Um erro comum entre iniciantes é acreditar que um pg_dump diário é suficiente para alta disponibilidade. Na prática, ele oferece RPO de até 24 horas, não permite PITR granular e pode levar horas para restaurar em bases grandes. Por outro lado, usar apenas pg_basebackup sem arquivar WAL gera um snapshots estáticos que envelhecem mal. Por isso, nesta aula vamos tratar as duas abordagens como complementares: backup lógico para flexibilidade e granularidade de objetos, e backup físico + WAL para recuperação completa e PITR. Nossos especialistas utilizam diariamente essa combinação em implantações na JRT Technology Solutions, sempre com testes automatizados de restauração.
Backup Lógico com pg_dump e pg_dumpall — Passo a Passo
O pg_dump é a ferramenta de backup lógico por excelência no PostgreSQL. Ele se conecta a um banco de dados específico e extrai seus objetos e dados em um dos quatro formatos disponíveis: plain (script SQL legível), custom (formato binário compactado, restaurado com pg_restore), directory (um diretório com arquivos por tabela, ideal para paralelismo) e tar (arquivo tar, menos utilizado). Cada formato tem vantagens: o plain pode ser editado e aplicado diretamente com psql, enquanto o custom e o directory permitem restauração seletiva de objetos e paralelismo com -j.
Antes de executar o pg_dump, analise o banco que será copiado e defina o objetivo do backup. Se você precisa migrar o banco loja inteiro, incluindo seus dados, o comando básico em formato plain é:
# Backup lógico em formato plain (script SQL) do banco "loja"
# -h: host; -U: usuário; -d: banco; -Fp: formato plain; -f: arquivo de saída
sudo -u postgres pg_dump -h localhost -U postgres -d loja -Fp -f /var/backups/postgresql/loja_plain_$(date +%F).sql
pg_dump: last built-in OID is 16383
pg_dump: reading schemas
pg_dump: reading user-defined tables
pg_dump: reading extensions
pg_dump: reading user-defined functions
pg_dump: reading user-defined types
pg_dump: reading procedural languages
pg_dump: reading user-defined aggregate functions
pg_dump: reading user-defined operators
pg_dump: reading user-defined access methods
pg_dump: reading user-defined operator classes
pg_dump: reading user-defined text search parsers
pg_dump: reading user-defined text search templates
pg_dump: reading user-defined text search dictionaries
pg_dump: reading user-defined text search configurations
pg_dump: reading user-defined foreign-data wrappers
pg_dump: reading user-defined foreign servers
pg_dump: reading default privileges
pg_dump: reading user-defined collations
pg_dump: reading user-defined conversions
pg_dump: reading type casts
pg_dump: reading table inheritance information
pg_dump: reading event triggers
pg_dump: finding extension tables
pg_dump: finding inheritance relationships
pg_dump: reading column info for interesting tables
pg_dump: finding table default expressions
pg_dump: finding functions with unsupported names
pg_dump: finding table check constraints
pg_dump: finding table partition information
pg_dump: finding table triggers
pg_dump: finding table dependencies
pg_dump: saving database definition
O comando acima gera um arquivo .sql contendo os comandos CREATE TABLE, COPY e restrições do banco loja. Para restauração, basta usar psql -d novo_banco -f arquivo.sql. No entanto, o formato plain não suporta restauração paralela nem seletiva. Para ambientes maiores ou para facilitar a automação, o formato custom com compressão é mais eficiente:
# Backup lógico em formato custom (binário comprimido)
# -Fc: custom; -Z 9: compressão máxima; -v: verbose
sudo -u postgres pg_dump -h localhost -U postgres -d loja -Fc -Z 9 -v -f /var/backups/postgresql/loja_custom_$(date +%F).backup
pg_dump: last built-in OID is 16383
pg_dump: reading schemas
...
pg_dump: saving database definition
pg_dump: dumping contents of table "clientes"
pg_dump: dumping contents of table "pedidos"
Com o formato custom, a restauração usa o pg_restore, que permite selecionar apenas objetos específicos, usar múltiplos jobs paralelos (-j) e validar o arquivo antes de aplicar. Para gerar um backup em directory, que também suporta paralelismo e restauração seletiva, execute:
# Backup lógico em formato directory (diretório com um arquivo por objeto)
# -Fd: directory; -j 4: 4 jobs paralelos; -v: verbose
sudo -u postgres pg_dump -h localhost -U postgres -d loja -Fd -j 4 -v -f /var/backups/postgresql/loja_dir_$(date +%F)
pg_dump: reading schemas
pg_dump: reading user-defined tables
pg_dump: reading extensions
pg_dump: creating pg_dump dump directory "/var/backups/postgresql/loja_dir_2026-08-26/"
pg_dump: dumping contents of table "clientes"
pg_dump: dumping contents of table "pedidos"
pg_dump: dumping contents of table "clientes"
pg_dump: dumping contents of table "pedidos"
pg_dump: finished item 1 TABLEDATA "clientes"
pg_dump: finished item 1 TABLEDATA "pedidos"
O pg_dumpall, por sua vez, é utilizado para extrair roles, tablespaces e parâmetros globais que não pertencem a um único banco. Ele gera um script SQL que deve ser restaurado antes dos backups individuais. Em um plano de backup completo, o pg_dumpall deve ser executado juntamente com os pg_dump de cada banco:
# Backup global (roles, tablespaces, parâmetros)
sudo -u postgres pg_dumpall -h localhost -U postgres -f /var/backups/postgresql/global_$(date +%F).sql --globals-only --verbose
pg_dumpall: executing SELECT oid, rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolconnlimit, rolpassword, rolvaliduntil, rolreplication, rolbypassrls, rolconfig, pg_catalog.shadow_pass(oid) FROM pg_authid WHERE rolname !~ '^pg_' ORDER BY 2
pg_dumpall: executing SELECT rolname, rolconfig FROM pg_authid WHERE rolname !~ '^pg_' ORDER BY 1
pg_dumpall: executing SELECT rolname, datname, pg_catalog.array_to_string(setconfig, E'\n') FROM pg_db_role_setting WHERE setdatabase <> 0 ORDER BY 1,2
pg_dumpall: executing SELECT rolname, datname, pg_catalog.array_to_string(setconfig, E'\n') FROM pg_db_role_setting WHERE setdatabase = 0 ORDER BY 1,2
pg_dumpall: executing SELECT rolname, attributes, comments FROM pg_authid JOIN pg_shdescription ON oid = objoid WHERE rolname !~ '^pg_' ORDER BY 1
pg_dumpall: executing SELECT rolname, datname, pg_catalog.array_to_string(setconfig, E'\n') FROM pg_db_role_setting WHERE setdatabase <> 0 ORDER BY 1,2
pg_dumpall: last built-in OID is 16383
Para verificar o conteúdo do arquivo global, você pode usar grep para listar as roles extraídas. Abaixo, a tabela resume as principais opções do pg_dump que você deve memorizar:
| Opção | Descrição | Exemplo |
|---|---|---|
-Fp |
Formato plain (script SQL) | -Fp |
-Fc |
Formato custom (binário, restauração com pg_restore) | -Fc |
-Fd |
Formato directory (paralelo e seletivo) | -Fd |
-Z <n> |
Nível de compressão (0 a 9) | -Z 9 |
-j <n> |
Jobs paralelos (apenas Fd) | -j 4 |
--clean |
Adiciona DROP antes de CREATE | --clean |
--if-exists |
Usa DROP IF EXISTS | --if-exists |
--create |
Inclui CREATE DATABASE no script | --create |
--no-owner |
Não restaura ownership (útil ao migrar) | --no-owner |
--no-privileges |
Não restaura GRANTs | --no-privileges |
--globals-only |
pg_dumpall: apenas roles e tablespaces | --globals-only |
Backup Físico com pg_basebackup — Configuração Completa e Execução
O pg_basebackup cria um backup físico completo do cluster PostgreSQL copiando todos os arquivos do diretório de dados e, opcionalmente, os segmentos de WAL necessários para tornar o backup consistente. Diferentemente do pg_dump, ele não se conecta a um único banco, mas ao cluster inteiro, e exige uma conexão com privilégios de replicação. Antes de executar a ferramenta, o servidor precisa estar configurado com wal_level = replica ou logical, um número adequado de max_wal_senders e, se você quiser usar slots de replicação, max_replication_slots.
Vamos configurar o arquivo postgresql.conf para habilitar as conexões de replicação e o fluxo de WAL. No Ubuntu/Debian, o arquivo está em /etc/postgresql/16/main/postgresql.conf; no Rocky Linux, em /var/lib/pgsql/16/data/postgresql.conf. Adicione ou altere as linhas abaixo. As demais entradas do arquivo permanecem com os valores padrão.
# Entradas relevantes para backup físico no postgresql.conf
# As demais linhas do arquivo permanecem com seus valores padrão.
wal_level = replica # replica permite backup físico e streaming
max_wal_senders = 10 # número de conexões de envio de WAL
max_replication_slots = 4 # slots para evitar remoção prematura de WAL
hot_standby = on # permite consultas em standby
archive_mode = on # ativa arquivamento de WAL (ver próxima seção)
archive_command = 'test ! -f /var/backups/postgresql/archive/%f && cp %p /var/backups/postgresql/archive/%f'
archive_timeout = 300 # força rotação de WAL a cada 5 minutos (opcional)
O parâmetro wal_level controla quanta informação é gravada no WAL. O valor mínimo para backup físico é replica, que registra todas as alterações de dados necessárias para replicação e PITR. O max_wal_senders define quantas conexões simultâneas de streaming de WAL o servidor aceita; o valor 10 é confortável para um ambiente de teste. O max_replication_slots permite criar slots de replicação, que impedem o servidor de descartar segmentos de WAL antes que o consumidor os tenha processado — essencial em ambientes com réplicas ou para PITR contínuo.
Depois de configurar o postgresql.conf, é necessário ajustar o pg_hba.conf para permitir conexões de replicação autenticadas. No mesmo diretório, edite o arquivo pg_hba.conf e adicione uma linha como a seguinte. O arquivo completo típico para esta aula ficaria:
# TYPE DATABASE USER ADDRESS METHOD
# Conteúdo completo do pg_hba.conf adaptado para esta aula
local all postgres peer
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
local replication all peer
host replication replicador 127.0.0.1/32 scram-sha-256
host replication replicador ::1/128 scram-sha-256
Perceba que criamos um usuário replicador com privilégio REPLICATION. Esse papel não precisa ser superusuário, apenas ter a permissão de replicação. Crie-o agora com os comandos SQL abaixo. Ele será usado pelo pg_basebackup.
# Criar usuário replicador com privilégio REPLICATION
sudo -u postgres psql <<'EOF'
CREATE ROLE replicador WITH LOGIN REPLICATION PASSWORD 'SenhaSegura123';
EOF
CREATE RO
Quer aprender na prática com especialistas?
A JRT Technology Solutions oferece treinamentos e implementação de PostgreSQL para equipes corporativas.