Instalar e configurar o PostgreSQL no Debian e no Ubuntu
Instalação a partir do pacote da distribuição ou do repositório PGDG, primeiro acesso através do utilizador postgres, criação da base de dados e do role, o pg_hba.conf explicado e um backup que aguenta mesmo.
No Debian e no Ubuntu, o PostgreSQL instala-se em dois minutos. As duas horas seguintes costumam ir-se embora porque ninguém consegue iniciar sessão. Este artigo leva a instalação até ao fim: escolha do pacote, primeiro acesso, base de dados e utilizador, as regras de acesso em pg_hba.conf e um backup que se sabe mesmo restaurável.
Todos os comandos correm como root. Se iniciar sessão com um utilizador normal, anteponha sudo. O número de versão 17 nos caminhos deve ser substituído pela versão que está realmente instalada no seu sistema.
Que versão do PostgreSQL vem em cada distribuição
A diferença mais importante entre os quatro sistemas habituais é a versão principal que vem do repositório da distribuição. Está fixada ao release e já não muda ao longo de todo o ciclo de vida da distribuição.
| Distribuição | PostgreSQL do repositório da distribuição |
| Debian 13 (trixie) | 17 |
| Debian 12 (bookworm) | 15 |
| Ubuntu 24.04 LTS (noble) | 16 |
| Ubuntu 22.04 LTS (jammy) | 14 |
Esta dispersão tem consequências práticas. Um dump feito no Debian 13 não se carrega sem mais no Ubuntu 22.04. E quem trabalha no Ubuntu 22.04 deve saber que, segundo a política de versões do PostgreSQL Global Development Group, o PostgreSQL 14 sai do suporte comunitário a 12 de novembro de 2026. O Ubuntu continua a fornecer atualizações de segurança para a 22.04 no âmbito do ciclo LTS, mas deixam de chegar correções upstream. Para projetos novos na 22.04, é um forte argumento para recorrer logo ao repositório PGDG.
O que está disponível no seu sistema mostra-se com uma olhadela à base de dados de pacotes, antes de instalar seja o que for:
apt update
apt-cache policy postgresql
A linha Candidato, ou Candidate num sistema em inglês, mostra um número de versão como 17+283. O número antes do sinal de mais é a versão principal do PostgreSQL, o resto é o número de versão do metapacote do Debian.
Instalação a partir do pacote da distribuição
Para a maioria dos casos, o pacote da distribuição é a escolha certa. Está integrado nas atualizações de segurança da distribuição, funciona com as bibliotecas do sistema e não cria problemas numa atualização de release.
apt install -y postgresql postgresql-contrib
O postgresql-contrib traz consigo as extensões incluídas, entre elas pgcrypto, uuid-ossp e pg_stat_statements. Sem esse pacote, muitas aplicações acabam por falhar mais tarde com um ERROR: could not open extension control file, e a procura da causa demora mais do que a instalação.
Durante a instalação, o Debian e o Ubuntu criam automaticamente um primeiro cluster chamado main e arrancam-no. Cluster significa aqui uma instância em execução com diretório de dados próprio, porta própria e configuração própria. Quem responde se isso resultou não é o código de saída do apt, mas sim isto:
pg_lsclusters
Na coluna Status, a saída tem de mostrar online:
Ver Cluster Port Status Owner Data directory Log file
17 main 5432 online postgres /var/lib/postgresql/17/main /var/log/postgresql/postgresql-17-main.log
Se ali estiver down, arranque o serviço à mão. O service postgresql start funciona nos quatro sistemas, incluindo em containers sem systemd. Num servidor normal, o systemctl start postgresql serve igualmente bem.
service postgresql start
pg_isready
O pg_isready responde com /var/run/postgresql:5432 - accepting connections e devolve o código de saída 0. Esta é a primeira prova sólida de que o servidor está acessível, e pode ser reaproveitada em scripts de monitorização.
Quando vale a pena o repositório PGDG e como integrá-lo corretamente
O repositório oficial em apt.postgresql.org disponibiliza em paralelo todas as versões principais suportadas para trixie, bookworm, noble e jammy. É a escolha certa quando precisa de uma versão principal concreta porque a aplicação a exige, quando precisa de extensões que o Debian não empacota, ou quando o estado da sua distribuição aponta para uma versão que sai do suporte em breve.
A chave pertence a um ficheiro próprio, já não ao chaveiro descontinuado do apt-key. O Debian 13 e o Ubuntu 24.04 preferem, além disso, o formato deb822 com a extensão .sources, que também funciona no Debian 12 e no Ubuntu 22.04:
apt install -y curl ca-certificates
install -d /usr/share/postgresql-common/pgdg
curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
cat > /etc/apt/sources.list.d/pgdg.sources <<EOF
Types: deb
URIs: https://apt.postgresql.org/pub/repos/apt
Suites: $(. /etc/os-release && echo $VERSION_CODENAME)-pgdg
Components: main
Signed-By: /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
EOF
A linha com $(. /etc/os-release ...) insere automaticamente trixie-pgdg, bookworm-pgdg, noble-pgdg ou jammy-pgdg. A seguir:
apt update
apt-cache policy postgresql-18
O pacote postgresql-common traz, para o mesmo efeito, um script pronto a usar, o /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh. É uma alternativa à chave e ao pgdg.sources acima, não um complemento. Se executar as duas coisas, o script cria adicionalmente um /etc/apt/sources.list.d/pgdg.list, e a partir daí o apt avisa em cada execução: W: Target Packages (main/binary-amd64/Packages) is configured multiple times in /etc/apt/sources.list.d/pgdg.list:1 and /etc/apt/sources.list.d/pgdg.sources:1. Quem preferir o script aos passos manuais acima instala antes também o gnupg, ou seja, apt install -y curl ca-certificates gnupg. É que a versão mais antiga do script, no Ubuntu 22.04, ainda importa a chave através do apt-key e, sem o gnupg, termina com E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation e código de saída 255. No Debian 13, no Debian 12 e no Ubuntu 24.04, a versão mais recente guarda a chave diretamente como .asc e corre sem pacote adicional.
A armadilha: dois clusters, duas portas
Se instalar agora uma nova versão principal num sistema que já tem o pacote da distribuição instalado, surge um segundo cluster. Esse não fica com a porta 5432, mas com a seguinte que estiver livre, ou seja, a 5433. As aplicações continuam a ligar-se à versão antiga, sem que nenhuma mensagem de erro o denuncie. É a causa mais frequente da frase "mas eu instalei o PostgreSQL 18 e o SELECT version() mostra 15".
apt install -y postgresql-18
pg_lsclusters
Agora aparecem ali duas linhas com portas diferentes. Se quiser passar os dados para a nova versão, a ferramenta certa é o pg_upgradecluster, não um dump feito à mão. Exige que os dois pacotes de servidor estejam instalados e deixa o cluster antigo parado, em vez de o apagar:
pg_upgradecluster 15 main
Verifique depois com o pg_lsclusters qual é o cluster que ficou na porta 5432 e teste a aplicação antes de remover definitivamente o cluster antigo com pg_dropcluster --stop 15 main. Este comando apaga o diretório de dados sem perguntar nada.
O primeiro acesso, e porque é que o root não pode usar o psql
O tropeção clássico logo a seguir à instalação:
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist
Isto não é um erro, é o comportamento esperado. O Debian e o Ubuntu configuram as ligações locais por socket com o método peer. O PostgreSQL pergunta então ao kernel sob que utilizador de sistema a ligação foi aberta e exige que exista um role de base de dados com o mesmo nome. Só existe o role postgres, por isso tem primeiro de mudar para esse utilizador de sistema.
su - postgres
A seguir, inicie o psql sem argumentos. Para sair da shell serve o exit. Para comandos avulsos a partir de um script, é mais prático mudar de utilizador em cada comando:
runuser -u postgres -- psql -c "SELECT version();"
Quem tiver o sudo instalado escreve antes sudo -u postgres psql -c "SELECT version();". As duas variantes são equivalentes. Com o sudo aparece muitas vezes o aviso could not change directory to "/root": Permission denied. Não tem consequências, porque o utilizador postgres não pode entrar no diretório de trabalho do root, mas o comando é executado à mesma.
Estas três consultas dizem-lhe com o que está a lidar, e são o primeiro passo em qualquer diagnóstico:
runuser -u postgres -- psql -c "SHOW server_version;"
runuser -u postgres -- psql -c "SHOW config_file;"
runuser -u postgres -- psql -c "SHOW hba_file;"
O último comando é particularmente útil. Indica o caminho que o servidor em execução lê de facto, tipicamente /etc/postgresql/17/main/pg_hba.conf. Se editar um ficheiro e nada mudar, quase sempre tem à sua frente a configuração de outro cluster.
Dentro do psql ajudam os meta-comandos: \l lista as bases de dados, \du os roles, \dt as tabelas da base de dados atual, \conninfo mostra com que identidade e a que servidor está ligado, e \q termina a sessão.
Criar a base de dados e o utilizador
Para cada aplicação deve criar-se um role próprio e uma base de dados própria. A ordem é importante, porque a base de dados deve pertencer diretamente ao role.
runuser -u postgres -- psql -c "CREATE ROLE appuser LOGIN PASSWORD 'ASuaPalavraPasseForte';"
runuser -u postgres -- psql -c "CREATE DATABASE appdb OWNER appuser;"
Desde o PostgreSQL 14 as palavras-passe são guardadas por omissão com scram-sha-256, o que vale portanto nos quatro sistemas aqui tratados. A palavra-passe não fica em texto simples na base de dados, mas fica no histórico da sua shell. Quem quiser evitar isso usa antes, dentro do psql, o \password appuser, que pergunta de forma interativa.
A armadilha desde o PostgreSQL 15: permission denied for schema public
Um comportamento que muitos guias mais antigos ainda não conhecem: a partir do PostgreSQL 15 já não é qualquer utilizador que pode criar objetos no esquema public. Isto afeta o Debian 12, o Debian 13 e o Ubuntu 24.04. Só o Ubuntu 22.04, com o PostgreSQL 14, ainda se comporta segundo o padrão antigo. O erro tem este aspeto:
ERROR: permission denied for schema public
LINE 1: CREATE TABLE clientes (id serial primary key);
O caminho limpo é o que foi mostrado acima: a base de dados pertence ao role. Desde a versão 15, o esquema public pertence ao role pg_database_owner, e o proprietário da base de dados é implicitamente membro dele. Quem tiver criado a base de dados sem OWNER atribui a permissão a posteriori. Repare que esta instrução tem de ser executada na base de dados afetada, e não na postgres:
runuser -u postgres -- psql -d appdb -c "GRANT ALL ON SCHEMA public TO appuser;"
A prova de que as permissões estão certas
Um CREATE ROLE sem erros ainda não significa que a aplicação consiga iniciar sessão. A prova é um início de sessão real por TCP seguido de um acesso de escrita. O PGPASSWORD serve aqui apenas para o teste, para o funcionamento permanente veja mais abaixo:
PGPASSWORD='ASuaPalavraPasseForte' psql -h 127.0.0.1 -U appuser -d appdb -c "SELECT current_user, current_database();"
PGPASSWORD='ASuaPalavraPasseForte' psql -h 127.0.0.1 -U appuser -d appdb -c "CREATE TABLE teste (id int);"
Se os dois comandos passarem, a combinação de role, palavra-passe, base de dados e permissões de esquema está completa. A tabela teste fica de propósito, porque o teste de backup mais abaixo precisa de pelo menos um objeto na base de dados, caso contrário verifica o vazio. Para controlo, liste os objetos:
runuser -u postgres -- psql -c "\du"
runuser -u postgres -- psql -c "\l"
Uma palavra sobre a codificação de caracteres: se a definição regional do sistema não estava em UTF-8 quando o cluster foi criado, a base de dados modelo pode estar em SQL_ASCII. Um CREATE DATABASE ... ENCODING 'UTF8' falha então com ERROR: new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII). A saída é usar TEMPLATE template0 na criação, e a solução limpa é um sistema com definição regional UTF-8.
Compreender o pg_hba.conf, a fonte de erro mais frequente
O ficheiro pg_hba.conf (host-based authentication) decide, antes de qualquer verificação de palavra-passe, se uma ligação chega sequer a ser aceite. É lido de cima para baixo, e a primeira linha correspondente ganha. Se nenhuma corresponder, a ligação é recusada. Uma regra generosa mais abaixo não lhe serve de nada se uma mais restritiva, colocada acima, pegar primeiro. É de longe o erro de configuração mais frequente.
O estado de origem no Debian e no Ubuntu é este:
# TYPE DATABASE USER ADDRESS METHOD
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
É assim nos quatro sistemas aqui tratados. Em versões mais antigas, por exemplo o Debian 11 com o PostgreSQL 13, as duas linhas host ainda trazem md5 em vez de scram-sha-256. O início de sessão por TCP funciona nos dois casos, mas já não deve contar com o md5.
As colunas significam o seguinte: local corresponde ao socket Unix, host a TCP com ou sem TLS, hostssl apenas a ligações com TLS. Seguem-se a base de dados, o role, a gama de rede em notação CIDR e o método. São quatro os métodos importantes. O peer verifica o utilizador de sistema e só funciona através do socket. O scram-sha-256 é o método moderno de palavra-passe e a escolha certa para tudo o que passa por TCP. O md5 está descontinuado e não deve voltar a aparecer em configurações novas. O trust deixa entrar qualquer um sem verificação e não tem lugar num servidor acessível.
As mensagens de erro, palavra por palavra
Quem as consegue distinguir poupa muita adivinhação:
FATAL: Peer authentication failed for user "appuser"
Está ligado através do socket, mas o seu utilizador de sistema tem um nome diferente do role. Ou muda de utilizador, ou liga-se com -h 127.0.0.1 para que a linha host passe a valer.
FATAL: no pg_hba.conf entry for host "198.51.100.4", user "appuser", database "appdb", no encryption
O servidor está acessível, mas nenhuma regra corresponde a esta combinação de endereço de origem, role e base de dados. Falta uma linha, ou a rede indicada na linha existente não cobre o endereço.
FATAL: password authentication failed for user "appuser"
A regra pega, mas a palavra-passe não está certa. Muitas vezes porque o role foi criado sem LOGIN, ou porque a palavra-passe ainda vem de uma instalação anterior.
psql: error: connection to server at "203.0.113.10", port 5432 failed: Connection refused
Aqui o pg_hba.conf nunca chegou a entrar em jogo. Ou o servidor não está a correr, ou não escuta neste endereço, ou uma firewall está a bloquear. Já a seguir há mais sobre isso.
Verificar as alterações antes de recarregar
O PostgreSQL oferece uma vista de sistema que mostra as regras já interpretadas, com número de linha e erros de sintaxe. Responde à pergunta de que regra o servidor vê realmente, em vez daquela que julga ter escrito:
runuser -u postgres -- psql -c "SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules;"
As alterações ao pg_hba.conf não precisam de reinício. Basta recarregar, e isso não corta nenhuma ligação existente:
runuser -u postgres -- psql -c "SELECT pg_reload_conf();"
Em alternativa, service postgresql reload. Um reinício a sério só é necessário se tiver alterado parâmetros como listen_addresses, port ou shared_buffers.
Permitir o acesso a partir do exterior
De origem, o PostgreSQL escuta apenas em localhost. É uma boa predefinição, e só deve abdicar dela quando for mesmo necessário. Duas coisas têm de coincidir: o servidor tem de escutar no endereço, e o pg_hba.conf tem de permitir a origem. Se faltar a primeira, obtém Connection refused; se faltar a segunda, obtém no pg_hba.conf entry.
A configuração fica em /etc/postgresql/17/main/postgresql.conf. O Debian traz para isso a ferramenta pg_conftool, que edita o ficheiro de forma mais fiável do que uma pesquisa no editor:
pg_conftool 17 main show listen_addresses
pg_conftool 17 main set listen_addresses '10.0.0.5,127.0.0.1'
Indique endereços concretos em vez de *. Num servidor com endereço público e endereço interno, fica assim ligado apenas à rede interna. A seguir acrescente uma regra no pg_hba.conf, tão restrita quanto possível:
host appdb appuser 10.0.0.0/24 scram-sha-256
Depois de um reinício com service postgresql restart, verifique primeiro em que endereços o processo escuta de facto. O ss -lntp | grep 5432 mostra os endereços associados. Se ali só constar 127.0.0.1:5432, a alteração não pegou, normalmente porque estava em causa um segundo cluster, ou porque um ficheiro em conf.d sobrepõe o valor.
A firewall precisa igualmente de uma regra, e com indicação de origem. Uma porta 5432 aberta sem restrições na Internet é apanhada por scanners em poucas horas:
ufw allow from 10.0.0.0/24 to any port 5432 proto tcp
Conselho honesto: na maioria dos casos a melhor solução é não abrir a porta de todo. Um túnel SSH com ssh -L 5432:127.0.0.1:5432 utilizador@servidor chega perfeitamente para acessos de manutenção. Para ligações permanentes entre vários servidores, uma rede WireGuard é a opção mais limpa, porque a base de dados continua então a escutar apenas num endereço privado. O Debian e o Ubuntu, aliás, ativam TLS por omissão com um certificado autoassinado, e por isso o sslmode=require funciona logo. Proteção real contra um atacante no caminho só a dá o sslmode=verify-full com um certificado em que o cliente confia.
Backup com o pg_dump, e a prova de que serve para alguma coisa
Para bases de dados individuais, o formato custom é a melhor escolha. É comprimido, permite um restauro seletivo e pode ser carregado em paralelo:
runuser -u postgres -- pg_dump -Fc -d appdb -f /var/lib/postgresql/appdb.dump
Um ponto que passa muitas vezes despercebido: o pg_dump não guarda roles nem palavras-passe. Estes existem ao nível de todo o cluster e têm de ser guardados à parte, senão, depois de um restauro, faltam exatamente os utilizadores de que a aplicação precisa:
runuser -u postgres -- pg_dumpall --globals-only -f /var/lib/postgresql/globals.sql
Quando as versões não combinam
pg_dump: error: server version: 17.5; pg_dump version: 15.10
pg_dump: error: aborting because of server version mismatch
A regra é esta: o pg_dump pode ser mais recente do que o servidor, nunca mais antigo. No Debian e no Ubuntu resolve-se facilmente, porque o /usr/bin/pg_dump é apenas um wrapper que escolhe a versão certa do programa. Instale o pacote postgresql-client-18 e a versão mais recente fica disponível. E com a extensão --cluster do Debian obriga o wrapper a usar um cluster concreto, aqui a versão 17, cluster main:
pg_dump --version
runuser -u postgres -- pg_dump --cluster 17/main -Fc -d appdb -f /var/lib/postgresql/appdb.dump
Manter as palavras-passe fora do script
Para backups automáticos, a palavra-passe pertence a um ficheiro .pgpass, no formato host:porta:base:utilizador:palavrapasse. O PostgreSQL ignora o ficheiro sem dizer nada se as permissões forem demasiado amplas. Igualmente importante é em que diretório pessoal ele se encontra, porque o ficheiro lido é sempre o do utilizador sob o qual o comando corre realmente. Um ~/.pgpass criado como root fica sem efeito enquanto o backup passar por runuser -u postgres, como neste artigo. Nesse caso conta a home do postgres:
touch /var/lib/postgresql/.pgpass
chown postgres:postgres /var/lib/postgresql/.pgpass
chmod 0600 /var/lib/postgresql/.pgpass
Vazio, o ficheiro fica igualmente sem efeito. Escreva uma linha por ligação, por exemplo 127.0.0.1:5432:appdb:appuser:ASuaPalavraPasseForte. Se, em vez disso, o seu job de backup correr diretamente como root, sem mudança de utilizador, o mesmo ficheiro pertence a /root/.pgpass.
Verificar o backup
Um ficheiro de backup que nunca foi restaurado não passa de uma suposição. O teste demora um minuto. Primeiro ver o índice, depois carregá-lo numa base de dados descartável e contar as tabelas:
runuser -u postgres -- pg_restore -l /var/lib/postgresql/appdb.dump | head -n 20
runuser -u postgres -- createdb appdb_restore_test
runuser -u postgres -- pg_restore -d appdb_restore_test /var/lib/postgresql/appdb.dump
runuser -u postgres -- psql -d appdb_restore_test -c "\dt"
runuser -u postgres -- dropdb appdb_restore_test
Se o \dt mostrar as mesmas tabelas do original, aqui pelo menos a tabela teste, o backup presta. Se, pelo contrário, o comando indicar Did not find any relations., a base de dados guardada estava vazia e o teste não prova nada. Na appdb, retire depois a tabela de teste com runuser -u postgres -- psql -d appdb -c "DROP TABLE teste;". Para o dia a dia basta uma entrada em /etc/cron.d que deixe os dois ficheiros com a data no nome e limpe os mais antigos. O importante é que os ficheiros saiam depois do servidor. Um backup no mesmo disco protege contra um DROP TABLE acidental, não contra uma avaria do hardware.
Quando o cluster não arranca
Se o serviço não arrancar, o estado do serviço costuma dizer apenas que algo falhou. A causa verdadeira está no log do cluster:
tail -n 30 /var/log/postgresql/postgresql-*-main.log
Há uma linha que pode ignorar sem receio. A mensagem já conhecida da primeira secção, FATAL: role "root" does not exist, vem quase sempre do pg_isready: a ferramenta monta a sua tentativa de ligação com o utilizador de sistema com sessão iniciada, ou seja, como root, e o servidor regista o role desconhecido. Ainda assim, o valor de retorno continua a ser 0, a saída diz accepting connections e o cluster está perfeitamente bem.
Em sistemas com systemd, o journalctl -u postgresql@17-main --no-pager -n 50 devolve as mesmas linhas. Repare na unit com número de versão: o postgresql.service é apenas um invólucro que arranca todos os clusters, e comunica sucesso mesmo quando um cluster isolado falhou. Por isso o pg_lsclusters é o controlo mais fiável.
Três mensagens cobrem a maioria dos casos. O could not bind IPv4 address "0.0.0.0": Address already in use significa que outro cluster está a ocupar a porta, veja a secção sobre os dois clusters. Uma mensagem de No space left on device ao escrever o postmaster.pid quer dizer simplesmente disco cheio, o que confirma com df -h. E os erros de permissões inválidas no diretório de dados surgem depois de execuções descuidadas de chmod ou chown: o /var/lib/postgresql/17/main tem de pertencer ao utilizador postgres e ter o modo 0700.
Para terminar, uma nota sobre a operação: na configuração de base, o PostgreSQL é conservador e está longe de aproveitar a memória de um servidor. Antes de mexer no shared_buffers e no work_mem, ative o pg_stat_statements do pacote contrib e veja que consultas custam tempo de facto. Na prática, o estrangulamento está quase sempre num índice em falta, e não nos parâmetros de memória.
Perguntas frequentes
Que versão do PostgreSQL recebo na minha distribuição?
Porque é que ao iniciar o psql aparece a mensagem "role root does not exist"?
O que significa "no pg_hba.conf entry for host" e como se resolve?
Porque é que o meu utilizador não consegue criar tabelas, apesar de poder usar a base de dados?
Tenho de reiniciar o PostgreSQL depois de alterar o pg_hba.conf?
O pg_dump chega como backup completo?
2026 KernelHost GmbH. Todos os direitos reservados. Este guia está protegido por direitos de autor. A sua republicação noutros sites, na íntegra, em parte ou de forma editada, não é permitida sem o nosso consentimento por escrito. Citações com indicação da fonte e ligação são expressamente bem-vindas.

