Docker e aplicações
Conexão PostgreSQL em Java: passo a passo com JDBC, SSL e pool
Do pom.xml ao primeiro SELECT: como conectar uma aplicação Java ao PostgreSQL com o driver pgJDBC, guardar a senha fora do código, exigir SSL com verificação do certificado, usar o pool HikariCP e resolver Connection refused, password authentication failed e no pg_hba.conf entry.
- Por equipe técnica da Hospedagem Segura
- Atualizado em 10/10/2026
- 11 min de leitura
Texto do artigo
Neste artigo
- Dependência do driver pgJDBC (Maven e Gradle)
- URL de conexão e credenciais fora do código
- Conexão PostgreSQL em Java com try-with-resources e PreparedStatement
- Conexão segura: SSL com sslmode verify-full
- Pool de conexões com HikariCP
- Erros comuns de conexão e como resolver
- Onde rodar a aplicação Java e o PostgreSQL
- Perguntas frequentes
Para fazer a conexão PostgreSQL em Java, você precisa de três coisas: o driver oficial pgJDBC no projeto, uma URL no formato jdbc:postgresql://servidor:5432/banco e um usuário que o PostgreSQL aceite vindo do IP da aplicação. Com isso, DriverManager.getConnection devolve a conexão; em produção, quem entrega as conexões é um pool como o HikariCP.
Este passo a passo foi testado com Java 21 (Eclipse Temurin), PostgreSQL 17.11 e pgJDBC 42.7.14, a versão mais recente do driver em outubro de 2026. No fim estão os três erros que mais aparecem, reproduzidos de verdade, e como resolver cada um: Connection refused, password authentication failed e no pg_hba.conf entry.
Dependência do driver pgJDBC (Maven e Gradle)
O driver do PostgreSQL para Java é o pgJDBC, escrito em Java puro e publicado no Maven Central. No Maven, a dependência é esta:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.14</version>
</dependency>A 42.7.14 roda em Java 8 ou mais novo e conecta ao PostgreSQL 8.4 em diante (os testes do projeto cobrem a partir da 9.1). Ela saiu em 7/10/2026 com duas correções de segurança, então vale atualizar quem está numa 42.7.x anterior. Sem Maven nem Gradle, baixe o JAR do Maven Central e coloque-o no classpath; o artigo sobre drivers JDBC mostra como baixar e conferir o hash.
URL de conexão e credenciais fora do código
A URL segue o formato jdbc:postgresql://servidor:porta/banco. Sem servidor, o driver usa localhost; sem porta, 5432; sem banco, um banco com o mesmo nome do usuário. Os parâmetros vêm depois do ponto de interrogação, separados por &. Os mais úteis:
- sslmode: disable, allow, prefer (o padrão), require, verify-ca ou verify-full.
- connectTimeout: quantos segundos esperar para abrir a conexão (padrão 10).
- socketTimeout: limite de espera por uma resposta, em segundos (padrão 0, sem limite).
- ApplicationName: nome que aparece na view pg_stat_activity do servidor, ótimo para saber quem está conectado.
- currentSchema: o schema usado quando a consulta não informa um.
Usuário e senha não entram no código nem no repositório. No servidor da aplicação, guarde-os num arquivo legível só pelo usuário que roda o Java e carregue as variáveis antes de iniciar:
DB_URL="jdbc:postgresql://db.exemplo.com.br:5432/loja?sslmode=verify-full&ApplicationName=loja-api"
DB_USER="app"
DB_PASSWORD="troque-por-uma-senha-forte"Conexão PostgreSQL em Java com try-with-resources e PreparedStatement
O programa abaixo conecta, mostra com qual usuário entrou e se a conexão está criptografada, e lista os produtos até um preço informado na linha de comando:
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ConexaoPostgres {
public static void main(String[] args) {
String url = System.getenv("DB_URL");
String usuario = System.getenv("DB_USER");
String senha = System.getenv("DB_PASSWORD");
BigDecimal limite = new BigDecimal(args.length > 0 ? args[0] : "100");
try (Connection conn = DriverManager.getConnection(url, usuario, senha)) {
mostraConexao(conn);
listaProdutos(conn, limite);
} catch (SQLException e) {
System.err.println("Erro: " + e.getMessage());
System.err.println("SQLState: " + e.getSQLState());
System.exit(1);
}
}
static void mostraConexao(Connection conn) throws SQLException {
String sql = "SELECT current_user, ssl, coalesce(version, '-') FROM pg_stat_ssl WHERE pid = pg_backend_pid()";
try (PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
rs.next();
System.out.println("Conectado como " + rs.getString(1) + " ao PostgreSQL "
+ conn.getMetaData().getDatabaseProductVersion());
System.out.println("SSL: " + (rs.getBoolean(2) ? "sim, " + rs.getString(3) : "não"));
}
}
static void listaProdutos(Connection conn, BigDecimal limite) throws SQLException {
String sql = "SELECT id, nome, preco FROM produtos WHERE preco <= ? ORDER BY preco";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setBigDecimal(1, limite);
try (ResultSet rs = ps.executeQuery()) {
System.out.println("Produtos até R$ " + limite + ":");
while (rs.next()) {
System.out.printf(" %d %-16s %8s%n",
rs.getInt("id"), rs.getString("nome"), rs.getBigDecimal("preco"));
}
}
}
}
}Três detalhes fazem diferença em produção. O try-with-resources fecha o ResultSet, o PreparedStatement e a Connection mesmo quando ocorre uma exceção; sem isso, cada erro deixa uma conexão aberta, até o servidor recusar novas com "too many clients". O PreparedStatement envia o SQL com marcadores ? e os valores separados, o que impede SQL injection e cuida dos tipos (BigDecimal para dinheiro, nunca double). E o SQLState impresso no catch identifica o tipo de falha: 08001 para problema de rede, 28P01 para senha, 28000 para regra do pg_hba.conf.

Para gravar, a lógica é a mesma, com uma transação: desligue o autocommit, execute e confirme com commit, ou desfaça com rollback se algo falhar. O RETURNING id devolve a chave gerada sem uma segunda consulta:
static int insere(Connection conn, String nome, BigDecimal preco) throws SQLException {
String sql = "INSERT INTO produtos (nome, preco) VALUES (?, ?) RETURNING id";
conn.setAutoCommit(false);
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, nome);
ps.setBigDecimal(2, preco);
try (ResultSet rs = ps.executeQuery()) {
rs.next();
int id = rs.getInt(1);
conn.commit();
return id;
}
} catch (SQLException e) {
conn.rollback();
throw e;
}
}Conexão segura: SSL com sslmode verify-full
No teste anterior, a linha "SSL: não" mostra que os dados, incluindo a autenticação, trafegaram sem criptografia. O padrão do driver, sslmode=prefer, só criptografa se o servidor oferecer e não confere o certificado; require também não confere. Para proteger a conexão de quem estiver no meio do caminho, use verify-full: o driver valida o certificado do servidor contra uma autoridade em que você confia e confere se o nome do servidor bate com o certificado.
No servidor do banco, ligue o SSL e, no pg_hba.conf, troque host por hostssl para recusar qualquer conexão sem criptografia:
# postgresql.conf
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
# pg_hba.conf: só o usuário app, no banco loja, vindo do IP da aplicação, com SSL
hostssl loja app 198.51.100.10/32 scram-sha-256No servidor da aplicação, o certificado da autoridade que assinou o do banco fica em ~/.postgresql/root.crt, o caminho padrão do driver no Linux (no Windows, %APPDATA%\postgresql\root.crt), ou em outro arquivo indicado pelo parâmetro sslrootcert. Se o servidor estiver com o SSL desligado, qualquer sslmode a partir de require falha com "The server does not support SSL."

A segunda tentativa da imagem mostra o verify-full trabalhando: o certificado foi emitido para db.exemplo.com.br, então a conexão pelo IP é recusada. Conecte sempre pelo nome que está no certificado.
Pool de conexões com HikariCP
Abrir conexão no PostgreSQL custa caro: o servidor cria um processo para cada uma, e há ainda a negociação de SSL e a autenticação. Numa API, abrir uma conexão por requisição pesa no tempo de resposta e esbarra no max_connections, que vem com 100. O HikariCP mantém algumas conexões abertas e as reaproveita. A versão atual é a 7.1.0, para Java 11 ou mais novo; ele registra os eventos pelo SLF4J, por isso o slf4j-simple (ou o logger que o projeto já usa):
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>7.1.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
</dependency>import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class PoolHikari {
public static void main(String[] args) throws Exception {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(System.getenv("DB_URL"));
config.setUsername(System.getenv("DB_USER"));
config.setPassword(System.getenv("DB_PASSWORD"));
config.setPoolName("loja");
config.setMaximumPoolSize(5);
try (HikariDataSource ds = new HikariDataSource(config)) {
for (int i = 1; i <= 3; i++) {
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT pg_backend_pid()");
ResultSet rs = ps.executeQuery()) {
rs.next();
System.out.println("Consulta " + i + ": conexão do pool, processo " + rs.getInt(1) + " no servidor");
}
}
}
}
}
O padrão do HikariCP é de até 10 conexões por pool. Some o pool de todas as instâncias da aplicação e deixe o total abaixo do max_connections, com folga para manutenção e backup. No Spring Boot, o HikariCP já é o pool padrão: basta informar spring.datasource.url, username e password.
Erros comuns de conexão e como resolver
Connection refused
O pedido chegou ao endereço, mas nada aceitou a conexão na porta 5432. As causas mais comuns: o PostgreSQL está parado, está configurado para escutar só em localhost (o padrão do listen_addresses) ou um firewall rejeita a porta. Teste a porta a partir do servidor da aplicação, sem o Java no meio:

No servidor do banco, confira com SHOW listen_addresses; no psql. Para aceitar conexões de outra máquina, informe o IP da interface de rede no postgresql.conf e reinicie o PostgreSQL, porque esse parâmetro só muda na inicialização:
listen_addresses = 'localhost,198.51.100.20'Libere a porta 5432 no firewall apenas para o IP da aplicação. Se a aplicação e o banco ficam na mesma VPS, nada disso é necessário: conecte por localhost e mantenha a porta fechada para a internet.
password authentication failed for user
O servidor encontrou uma regra no pg_hba.conf para a conexão, mas a senha não confere. A aplicação recebe a mesma mensagem quando o usuário não existe; só o log do servidor mostra a diferença e qual linha do pg_hba.conf foi usada:
2026-10-10 02:54:01.534 UTC [140] FATAL: password authentication failed for user "app"
2026-10-10 02:54:01.534 UTC [140] DETAIL: Connection matched file "/var/lib/postgresql/data/pg_hba.conf" line 128: "host loja app 198.51.100.10/32 scram-sha-256"Confira a senha no banco.env e, se precisar, redefina no psql com \password app, que não deixa a senha no histórico.

no pg_hba.conf entry for host
Nenhuma linha do pg_hba.conf combina com a conexão. A mensagem traz tudo o que você precisa comparar: o IP de origem, o usuário, o banco e se havia criptografia. No exemplo, a aplicação tentou o banco postgres, mas a regra só libera o banco loja. Os casos mais comuns são a aplicação mudar de servidor (IP novo), o nome do banco errado na URL e a regra hostssl com uma conexão sem SSL. Para ver o arquivo em uso e as regras que o servidor carregou:
SHOW hba_file;
SELECT line_number, type, database, user_name, address, auth_method
FROM pg_hba_file_rules;Ajuste a linha, ou acrescente uma para o novo IP, e recarregue com SELECT pg_reload_conf(); sem reiniciar o banco.
Onde rodar a aplicação Java e o PostgreSQL
Uma aplicação Java com PostgreSQL próprio precisa de um servidor em que você escolha as versões, edite o postgresql.conf e o pg_hba.conf e controle o firewall. A VPS Linux da Hospedagem Segura entrega acesso root, armazenamento NVMe e IPv4 dedicado, com Ubuntu, Debian, AlmaLinux ou Rocky Linux, para rodar o Java e o PostgreSQL na mesma máquina ou em VPS separadas. A administração e a estratégia de backup do banco ficam com você; quem prefere receber a VPS pronta, com backups periódicos e ajuda técnica mensal, pode escolher o VPS Assistido.
Perguntas frequentes
Qual é a URL de conexão do PostgreSQL em Java?
É jdbc:postgresql://servidor:5432/nome_do_banco, com parâmetros opcionais depois do ponto de interrogação, como sslmode=verify-full. Sem a porta, o driver usa 5432; sem o servidor, localhost.
Preciso de Class.forName("org.postgresql.Driver")?
Não. Com o JAR do pgJDBC no classpath, o driver se registra sozinho pelo mecanismo de service provider do Java, e DriverManager.getConnection já o encontra. O Class.forName só era obrigatório em versões muito antigas do Java.
Qual versão do pgJDBC usar com Java 21?
Use a 42.7.14, a mais recente em outubro de 2026, que funciona com Java 8 ou mais novo, incluindo o Java 21. Ela corrigiu duas falhas de segurança das versões 42.7.x anteriores.
Como forçar SSL na conexão do Java com o PostgreSQL?
No cliente, use sslmode=verify-full na URL e tenha o certificado da autoridade em ~/.postgresql/root.crt ou no parâmetro sslrootcert. No servidor, ligue ssl = on e use hostssl no pg_hba.conf, para que conexões sem criptografia sejam recusadas.
Como resolver "no pg_hba.conf entry for host"?
Acrescente ao pg_hba.conf uma linha que combine com o IP, o usuário e o banco citados na mensagem e recarregue a configuração com SELECT pg_reload_conf();. Confira também se a URL aponta para o banco certo e se a regra exige SSL (hostssl) enquanto o cliente conecta sem.
Leia também
- Docker e aplicaçõesDrivers JDBC: o que são, como funcionam e quais usar em 2026JDBC é a API padrão do Java para falar com bancos de dados, e o driver é o JAR que leva essas chamadas ao PostgreSQL, ao MySQL, ao MariaDB ou ao SQL Server. Veja como funciona, as versões atuais de cada driver, a URL de conexão, os erros mais comuns e o pool HikariCP, com testes reais.9 min de leitura10/10/2026
- Docker e aplicaçõesComo instalar Docker e Docker Compose no Ubuntu ServerO jeito recomendado de instalar o Docker em um servidor Ubuntu é pelo repositório oficial da Docker, que já traz o plugin do Compose. Veja o passo a passo e os cuidados de segurança.3 min de leitura10/10/2026
- Primeiros passosVPS ou servidor dedicado: diferenças e como escolherO VPS é um servidor virtual com recursos reservados dentro de uma máquina maior; o dedicado é a máquina inteira só para você. A escolha depende de carga, previsibilidade e orçamento.4 min de leitura10/10/2026
Java e PostgreSQL no seu servidor
VPS Linux com acesso root, armazenamento NVMe e IPv4 dedicado para rodar a sua aplicação Java e o PostgreSQL com a configuração que você precisa.