Cuando algo falla en Odoo → PgBouncer → PostgreSQL, los errores de auth suelen parecer “misteriosos”… hasta que separas el problema en dos saltos:
Cliente (Odoo/psql) → PgBouncer (auth de entrada)
PgBouncer → PostgreSQL (auth de salida)
PgBouncer hace ambas cosas y, por diseño, el auth_file puede usarse tanto para validar clientes como para autenticarse contra el backend (si el backend pide password). PgBouncer
Este post es un playbook de debugging “copiar/pegar”.
1) Triage rápido: ¿dónde se rompe?
Prueba mínima (sin Odoo): conecta a PgBouncer con psql
psql "host=PGBOUNCER_HOST port=6432 dbname=TU_DB user=odoo"
Si esto falla, el problema está entre cliente → PgBouncer (userlist, auth_type, TLS, HBA en PgBouncer, etc.).
Si esto funciona pero Odoo falla, suele ser: dbfilter, base equivocada, password diferente, o conectividad desde otra IP/host.
2) Activa señales útiles (sin “debug eterno”)
En pgbouncer.ini, asegúrate de tener logs que realmente expliquen auth:
[pgbouncer] log_connections = 1 log_disconnections = 1 log_pooler_errors = 1 verbose = 1
log_connections: loguea logins exitosos. PgBouncer
log_disconnections: loguea desconexiones con motivo. PgBouncer
log_pooler_errors: loguea errores que PgBouncer envía al cliente. PgBouncer
verbose: sube verbosidad (hasta 3). PgBouncer
Si rotas el logfile: PgBouncer mantiene el archivo abierto; tras rotación, haz kill -HUP o RELOAD para que reabra el log. PgBouncer+1
3) Entra a la consola admin de PgBouncer (tu mejor amigo)
Conecta al “admin DB” pgbouncer:
psql "host=PGBOUNCER_HOST port=6432 dbname=pgbouncer user=ADMIN_USER"
Asegura que ADMIN_USER esté en admin_users (o al menos en stats_users si solo quieres lectura). PgBouncer
Comandos imprescindibles (orden recomendado)
SHOW CONFIG; SHOW USERS; SHOW DATABASES; SHOW CLIENTS; SHOW SERVERS; SHOW POOLS; SHOW STATS;
Y cuando cambiaste config o userlist:
RELOAD;
RELOAD recarga el config y también los archivos auth_file y auth_hba_file. PgBouncer+1
Tip potente: puedes activar logs “en caliente” con:
SET log_connections = 1; SET verbose = 2;
(esto se ejecuta en la consola admin y cambia settings de PgBouncer). PgBouncer
4) El 80% de los “auth failed” está en auth_type + auth_file
4.1 Verifica auth_type (y su trampa más común)
PgBouncer define claramente:
scram-sha-256: auth_file debe tener SCRAM secrets o passwords en texto plano. PgBouncer+1
trust: no valida password, pero el usuario igual debe existir en auth_file. PgBouncer
hba: el método real sale del auth_hba_file. PgBouncer
4.2 Valida el formato real del userlist.txt
El formato esperado es:
"username1" "password" ... "username2" "md5abcdef..." ... "username3" "SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>"
Deben ser al menos 2 campos entre comillas.
PgBouncer ignora el resto de la línea.
Comillas dobles dentro de un campo se escapan como "". PgBouncer
5) ¿Tu problema es de salida? (PgBouncer → PostgreSQL)
Este caso es típico cuando:
PgBouncer acepta al cliente, pero luego falla al abrir conexión al backend.
Ves errores de SASL/SCRAM o “password authentication failed” aunque el userlist “parece correcto”.
Punto clave (🔥): SCRAM secret no siempre sirve para loguear al backend
PgBouncer explica una limitación importante:
Los secretos del auth_file sirven para 2 cosas:
verificar passwords de clientes entrantes
usarlos como password para conexiones al backend (si el backend lo requiere) PgBouncer
Pero: un SCRAM secret solo puede usarse para loguearse al servidor si se cumplen condiciones estrictas (SCRAM también en client auth, sin usuario forzado en la DB definition, y secret idéntico en PgBouncer y Postgres: misma sal e iteraciones). Esto existe por una propiedad de SCRAM: el secreto almacenado no sirve por sí solo para derivar credenciales de login. PgBouncer
👉 Traducción operativa:
Si tu Postgres exige SCRAM y PgBouncer no conoce o el password en claro o el SCRAM secret exacto, vas a ver auth fallar “del lado backend”.
6) Si usas auth_user + auth_query, debuggea esto primero
Cuando auth_user está configurado:
Usuarios que no están en auth_file se consultan con auth_query en la DB usando auth_user.
La password de auth_user se toma del auth_file. PgBouncer
PgBouncer incluso trae un auth_query default que consulta pg_authid y considera rolvaliduntil. PgBouncer
Pitfall clásico: acceso directo a pg_authid requiere permisos altos; PgBouncer recomienda usar un usuario no-superuser que llame una función SECURITY DEFINER. PgBouncer+1
Qué mirar en logs cuando falla aquí
¿Puede PgBouncer conectarse a la auth_dbname/DB destino?
¿El auth_user tiene password correcta en auth_file?
¿El auth_query devuelve 2 columnas (usuario + password/secret) y no NULL por expiración?
7) “Diccionario” de errores típicos y qué significan
no such user
Casi siempre:
usuario no está en auth_file, y no hay auth_user activo; o
el userlist no se recargó (faltó RELOAD). PgBouncer+1
SASL authentication failed (SCRAM)
password incorrecta o userlist mal.
o PgBouncer→Postgres falla porque no tiene credencial válida para SCRAM (ver sección 5). PgBouncer+1
“Cambie el userlist y no pasa nada”
Solución estándar:
edita userlist.txt
RELOAD; (consola admin)
Porque RELOAD recarga también auth_file y auth_hba_file. PgBouncer
8) Checklist final (modo “anti-incendio”)
Probé con psql directo a PgBouncer (sin Odoo)
Entré a dbname=pgbouncer y corrí SHOW USERS/POOLS/CLIENTS/SERVERS
Confirmé auth_type y si aplica auth_hba_file PgBouncer+1
Validé formato de userlist.txt (comillas, 2 campos mínimo) PgBouncer
Después de cambios: RELOAD PgBouncer
Si hay SCRAM: entendí la limitación del SCRAM secret para login al backend PgBouncer
Si uso auth_user/auth_query: revisé permisos y el query default/resultado PgBouncer+1