Banco de Dados

Conectar sua aplicação ao banco

Este guia mostra como conectar uma aplicação ao PostgreSQL ou ao MariaDB da Zenifra com os drivers mais usados em Python, Node.js e Bun. Todas as conexões usam TLS e validam o certificado e o hostname do banco.

Antes de começar

  1. Abra o banco no console e copie a URI de conexão. A senha completa aparece somente na criação ou depois de uma rotação de senha.
  2. No projeto da aplicação, abra Variáveis de Ambiente e crie DATABASE_URL com essa URI.
  3. Use sempre o host mostrado no console, no formato postgresql-<id>.managed.zenifra.com ou mariadb-<id>.managed.zenifra.com. O certificado é emitido para esse nome, então conexões pelo endereço IP falham na validação.

Não desative a validação do certificado para "fazer funcionar": não use sslmode=require, sslmode=disable, rejectUnauthorized: false ou opções equivalentes. Os ajustes abaixo resolvem os casos conhecidos mantendo a validação completa.

Resumo por driver

BancoLinguagemDriverO que fazer
PostgreSQLTerminalpsqlUse a URI do console sem alterações
PostgreSQLPythonpsycopg / psycopg2 (pacotes binary)Defina SSL_CERT_FILE
PostgreSQLPythonasyncpgRemova sslrootcert da URI e passe um contexto TLS
PostgreSQLNode.js e Bunpg (node-postgres)Remova &sslrootcert=system da URI
PostgreSQLNode.js e Bunpostgres (postgres.js)Use a URI do console sem alterações
PostgreSQLBunBun.sqlUse a URI do console sem alterações
MariaDBNode.jsmariadbUse a URI do console sem alterações
MariaDBNode.js e Bunmysql2Configure ssl como objeto, com verifyIdentity
MariaDBPythonPyMySQLInforme o bundle de CAs e ative a verificação de identidade

PostgreSQL

A URI PostgreSQL do console termina com ?sslmode=verify-full&sslrootcert=system. Esses parâmetros exigem TLS, validam a cadeia de certificados pelo armazenamento confiável do sistema e conferem o hostname. Alguns drivers não entendem sslrootcert=system e precisam dos ajustes abaixo.

psql

psql "$DATABASE_URL"

Versões do psql que não suportam sslrootcert=system aceitam o caminho do bundle de CAs do sistema no lugar de system, por exemplo sslrootcert=/etc/ssl/certs/ca-certificates.crt.

Python com psycopg ou psycopg2

Os pacotes psycopg[binary] e psycopg2-binary trazem uma biblioteca TLS própria, que não encontra os certificados do sistema. Sem ajuste, a conexão falha com SSL error: certificate verify failed.

Defina a variável de ambiente abaixo no projeto. Ela aponta o driver para o bundle de CAs do sistema, e a URI continua igual:

SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
import os
import psycopg

with psycopg.connect(os.environ["DATABASE_URL"]) as conn:
    conn.execute("SELECT 1")

Aplicações Python publicadas na Zenifra sem Dockerfile próprio já recebem essa variável. Se a aplicação foi publicada antes de 21/10/2026, faça um novo deploy. Com Dockerfile próprio, adicione ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt e confirme que a imagem instala o pacote ca-certificates. Django e SQLAlchemy usam o psycopg ou o psycopg2 por baixo e seguem a mesma regra.

Python com asyncpg

O asyncpg trata sslrootcert=system como o nome de um arquivo e falha com FileNotFoundError. Remova o sslrootcert da URI e passe um contexto TLS que valida certificado e hostname:

import os
import ssl
import asyncpg

dsn = os.environ["DATABASE_URL"].split("?")[0]
conn = await asyncpg.connect(dsn, ssl=ssl.create_default_context())

Node.js e Bun com pg (node-postgres)

O pg trata sslrootcert=system como o nome de um arquivo e falha com ENOENT: no such file or directory, open 'system'. Remova &sslrootcert=system e mantenha sslmode=verify-full. Assim, o driver valida certificado e hostname com os CAs do próprio Node.js:

DATABASE_URL=postgresql://app:<senha>@<host>:<porta>/app?sslmode=verify-full
import pg from 'pg'

const client = new pg.Client({ connectionString: process.env.DATABASE_URL })
await client.connect()

Node.js e Bun com postgres.js

import postgres from 'postgres'

const sql = postgres(process.env.DATABASE_URL)
await sql`SELECT 1`

Bun com Bun.sql

const sql = new Bun.SQL(process.env.DATABASE_URL)
await sql`SELECT 1`

MariaDB

A URI MariaDB do console usa o formato mariadb://app:<senha>@<host>:<porta>/app?ssl=true.

Node.js com mariadb

import mariadb from 'mariadb'

const conn = await mariadb.createConnection(process.env.DATABASE_URL)
await conn.query('SELECT 1')

No Bun, use o mysql2 em vez do conector mariadb.

Node.js e Bun com mysql2

O mysql2 não aceita ssl=true na URI e falha com SSL profile must be an object. Passe os dados de conexão como objeto. O verifyIdentity: true é necessário para o driver conferir o hostname do certificado:

import mysql from 'mysql2/promise'

const url = new URL(process.env.DATABASE_URL)
const conn = await mysql.createConnection({
  host: url.hostname,
  port: Number(url.port),
  user: decodeURIComponent(url.username),
  password: decodeURIComponent(url.password),
  database: url.pathname.slice(1),
  ssl: { rejectUnauthorized: true, verifyIdentity: true },
})

Python com PyMySQL

import os
from urllib.parse import unquote, urlsplit

import pymysql

url = urlsplit(os.environ["DATABASE_URL"])
conn = pymysql.connect(
    host=url.hostname,
    port=url.port,
    user=unquote(url.username),
    password=unquote(url.password),
    database=url.path.lstrip("/"),
    ssl_ca="/etc/ssl/certs/ca-certificates.crt",
    ssl_verify_cert=True,
    ssl_verify_identity=True,
)

O caminho /etc/ssl/certs/ca-certificates.crt existe em imagens Debian, Ubuntu e Alpine com o pacote ca-certificates instalado. Em outros sistemas, use o bundle de CAs correspondente.

Erros comuns

MensagemCausaComo resolver
SSL error: certificate verify failedDriver Python com biblioteca TLS própria não encontra os CAs do sistemaDefina SSL_CERT_FILE como em psycopg ou psycopg2
ENOENT: no such file or directory, open 'system'O pg trata sslrootcert=system como arquivoRemova &sslrootcert=system da URI
FileNotFoundError no asyncpgO asyncpg trata sslrootcert=system como arquivoRemova sslrootcert e passe ssl=ssl.create_default_context()
SSL profile must be an objectO mysql2 não aceita ssl=true na URIPasse ssl como objeto
Hostname/IP does not match certificate's altnames ou IP address mismatchA conexão usa um IP ou outro nome no lugar do host do consoleUse o host exato mostrado no console
password authentication failed ou Access deniedA senha na DATABASE_URL não é a atualConfira a senha ou gere uma nova na edição do banco e atualize a variável na aplicação

Próximos passos

Última atualização em

Nessa página