Instalar y configurar PostgreSQL en Debian y Ubuntu

Publicado el 18 min de lectura

Instalación desde el paquete de la distribución o desde el repositorio PGDG, primer acceso con el usuario postgres, creación de base de datos y rol, pg_hba.conf explicado y un backup que de verdad aguanta.

PostgreSQL se instala en dos minutos en Debian y Ubuntu. Las dos horas siguientes se suelen ir en un único problema: nadie consigue iniciar sesión. Este artículo lleva la instalación hasta el final: elección del paquete, primer acceso, base de datos y usuario, las reglas de acceso en pg_hba.conf y un backup del que sabes con certeza que se puede restaurar.

Todos los comandos se ejecutan como root. Si inicias sesión con una cuenta normal, antepón sudo. El número de versión 17 que aparece en las rutas debes sustituirlo por la versión que realmente esté instalada en tu sistema.

Qué versión de PostgreSQL trae cada distribución

La diferencia más importante entre los cuatro sistemas habituales es la versión mayor que llega desde el repositorio de la distribución. Está fijada al release y ya no cambia durante toda la vida útil de la distribución.

DistribuciónPostgreSQL del repositorio de la distribución
Debian 13 (trixie)17
Debian 12 (bookworm)15
Ubuntu 24.04 LTS (noble)16
Ubuntu 22.04 LTS (jammy)14

Esta dispersión tiene consecuencias muy prácticas. Un dump generado en Debian 13 no se restaura sin más en Ubuntu 22.04. Y si trabajas sobre Ubuntu 22.04, conviene saber que PostgreSQL 14 sale del soporte comunitario el 12 de noviembre de 2026, según la política de versiones del PostgreSQL Global Development Group. Ubuntu sigue publicando actualizaciones de seguridad para 22.04 dentro del ciclo LTS, pero ya no incorpora correcciones upstream. Para un proyecto nuevo sobre 22.04, ese es un argumento de peso para recurrir directamente al repositorio PGDG.

Antes de instalar nada, un vistazo a la base de datos de paquetes te dice qué hay disponible en tu sistema:

apt update
apt-cache policy postgresql

La línea Candidato, o Candidate en un sistema en inglés, muestra un número de versión como 17+283. La cifra anterior al signo más es la versión mayor de PostgreSQL, el resto es el número de versión del metapaquete de Debian.

Instalación desde el paquete de la distribución

Para la mayoría de los casos de uso, el paquete de la distribución es la elección correcta. Está integrado en las actualizaciones de seguridad del sistema, funciona con las bibliotecas presentes y no da problemas en una actualización de release.

apt install -y postgresql postgresql-contrib

postgresql-contrib aporta las extensiones que se entregan con el servidor, entre ellas pgcrypto, uuid-ossp y pg_stat_statements. Sin ese paquete, muchas aplicaciones fallan más tarde con un ERROR: could not open extension control file, y localizar el fallo lleva más tiempo que la propia instalación.

Durante la instalación, Debian y Ubuntu crean automáticamente un primer clúster llamado main y lo arrancan. Clúster significa aquí una instancia en ejecución con su propio directorio de datos, su propio puerto y su propia configuración. Quien confirma que todo ha funcionado no es el código de salida de apt, sino esto:

pg_lsclusters

La salida tiene que mostrar online en la columna Status:

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

Si ahí pone down, arranca el servicio a mano. service postgresql start funciona en los cuatro sistemas, también en contenedores sin systemd. En un servidor normal, systemctl start postgresql sirve igual de bien.

service postgresql start
pg_isready

pg_isready responde con /var/run/postgresql:5432 - accepting connections y devuelve el código de salida 0. Esa es la primera prueba sólida de que el servidor está accesible, y se reutiliza tal cual en scripts de monitorización.

Cuándo merece la pena el repositorio PGDG y cómo integrarlo bien

El repositorio oficial en apt.postgresql.org ofrece en paralelo todas las versiones mayores soportadas para trixie, bookworm, noble y jammy. Es la elección correcta si necesitas una versión mayor concreta porque la aplicación la exige, si necesitas extensiones que Debian no empaqueta, o si el estado de tu distribución apunta a una versión cuyo soporte termina pronto.

La clave va en un archivo propio, ya no en el llavero apt-key, que está obsoleto. Debian 13 y Ubuntu 24.04 prefieren además el formato deb822 con la extensión .sources, que sin embargo también funciona en Debian 12 y 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

La línea con $(. /etc/os-release ...) inserta automáticamente trixie-pgdg, bookworm-pgdg, noble-pgdg o jammy-pgdg. Después:

apt update
apt-cache policy postgresql-18

El paquete postgresql-common trae para el mismo fin un script ya preparado, /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh. Es una alternativa a la clave y al pgdg.sources de arriba, no un complemento. Si ejecutas ambas cosas, el script crea además un /etc/apt/sources.list.d/pgdg.list, y apt avisa luego en cada ejecución: 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. Si prefieres el script a los pasos manuales de arriba, instala antes también gnupg, es decir apt install -y curl ca-certificates gnupg. La versión más antigua del script en Ubuntu 22.04 todavía importa la clave a través de apt-key y sin gnupg aborta con E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation y el código de salida 255. En Debian 13, Debian 12 y Ubuntu 24.04, la versión más reciente deposita la clave directamente como .asc y se ejecuta sin paquetes adicionales.

La trampa: dos clústeres, dos puertos

Si ahora instalas una versión mayor nueva en un sistema donde ya está el paquete de la distribución, aparece un segundo clúster. Ese no recibe el puerto 5432, sino el siguiente que esté libre, o sea 5433. Las aplicaciones siguen conectándose a la versión antigua, sin que ningún mensaje de error lo indique. Es la causa más frecuente de la frase "pero si he instalado PostgreSQL 18, y SELECT version() muestra 15".

apt install -y postgresql-18
pg_lsclusters

Ahora aparecen ahí dos líneas con puertos distintos. Si quieres traspasar los datos a la versión nueva, la herramienta adecuada es pg_upgradecluster, no un dump hecho a mano. Requiere que los dos paquetes de servidor estén instalados y deja el clúster antiguo parado en lugar de borrarlo:

pg_upgradecluster 15 main

Comprueba después con pg_lsclusters qué clúster ocupa el puerto 5432 y prueba la aplicación antes de eliminar definitivamente el clúster antiguo con pg_dropcluster --stop 15 main. Ese comando borra el directorio de datos sin preguntar.

El primer acceso, y por qué root no puede usar psql

El tropiezo clásico justo después de la instalación:

psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  role "root" does not exist

No es un fallo, es el comportamiento esperado. Debian y Ubuntu configuran las conexiones locales por socket con el método peer. PostgreSQL le pregunta entonces al kernel con qué usuario del sistema se abrió la conexión y exige que exista un rol de base de datos con el mismo nombre. Solo existe el rol postgres, así que primero tienes que cambiar a ese usuario del sistema.

su - postgres

Después arrancas psql sin argumentos. Para salir de la shell sirve exit. Para comandos sueltos lanzados desde un script resulta más práctico cambiar de usuario en cada comando:

runuser -u postgres -- psql -c "SELECT version();"

Si tienes sudo instalado, escribe en su lugar sudo -u postgres psql -c "SELECT version();". Las dos variantes son equivalentes. Con sudo aparece a menudo el aviso could not change directory to "/root": Permission denied. No tiene consecuencias, porque el usuario postgres no puede entrar en el directorio de trabajo de root, pero el comando se ejecuta igualmente.

Estas tres consultas te dicen a qué te enfrentas, y son el primer paso en cualquier 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;"

El último comando es especialmente útil. Indica la ruta que el servidor en ejecución lee de verdad, normalmente /etc/postgresql/17/main/pg_hba.conf. Si editas un archivo y no cambia nada, casi siempre tienes delante la configuración de otro clúster.

Dentro de psql ayudan los metacomandos: \l lista las bases de datos, \du los roles, \dt las tablas de la base de datos actual, \conninfo muestra como quién y a dónde estás conectado, y \q termina la sesión.

Crear la base de datos y el usuario

Cada aplicación merece un rol propio y una base de datos propia. El orden importa, porque la base de datos debe pertenecer directamente al rol.

runuser -u postgres -- psql -c "CREATE ROLE appuser LOGIN PASSWORD 'TuContraseñaSegura';"
runuser -u postgres -- psql -c "CREATE DATABASE appdb OWNER appuser;"

Desde PostgreSQL 14, las contraseñas se guardan por defecto con scram-sha-256, así que eso vale en los cuatro sistemas tratados aquí. La contraseña no llega en texto plano a la base de datos, pero sí queda en el historial de tu shell. Si quieres evitarlo, usa dentro de psql el comando \password appuser, que la pide de forma interactiva.

La trampa desde PostgreSQL 15: permission denied for schema public

Un comportamiento que muchas guías antiguas todavía desconocen: a partir de PostgreSQL 15 ya no todos los usuarios pueden crear objetos en el esquema public. Afecta a Debian 12, Debian 13 y Ubuntu 24.04. Solo Ubuntu 22.04 con PostgreSQL 14 se comporta aún según el patrón antiguo. El error tiene este aspecto:

ERROR:  permission denied for schema public
LINE 1: CREATE TABLE clientes (id serial primary key);

El camino limpio es el que se ha mostrado arriba: la base de datos pertenece al rol. Desde la versión 15, el esquema public pertenece al rol pg_database_owner, y el propietario de cada base de datos es miembro implícito de ese rol. Si en cambio creaste la base de datos sin OWNER, concede el permiso a posteriori. Ten en cuenta que esa instrucción debe ejecutarse en la base de datos afectada, no en postgres:

runuser -u postgres -- psql -d appdb -c "GRANT ALL ON SCHEMA public TO appuser;"

La prueba de que los permisos son correctos

Un CREATE ROLE sin errores todavía no significa que la aplicación pueda iniciar sesión. La prueba es un inicio de sesión real por TCP seguido de un acceso de escritura. PGPASSWORD aquí solo está pensado para el test, para el uso permanente mira más abajo:

PGPASSWORD='TuContraseñaSegura' psql -h 127.0.0.1 -U appuser -d appdb -c "SELECT current_user, current_database();"
PGPASSWORD='TuContraseñaSegura' psql -h 127.0.0.1 -U appuser -d appdb -c "CREATE TABLE prueba (id int);"

Si los dos comandos pasan, la combinación de rol, contraseña, base de datos y permisos de esquema está completa. La tabla prueba se queda ahí a propósito, porque el test de backup de más abajo necesita al menos un objeto en la base de datos, de lo contrario no comprueba nada. Para verificarlo, lista los objetos:

runuser -u postgres -- psql -c "\du"
runuser -u postgres -- psql -c "\l"

Una nota sobre la codificación de caracteres: si la configuración regional del sistema no estaba en UTF-8 al crear el clúster, la base de datos plantilla puede ser SQL_ASCII. Un CREATE DATABASE ... ENCODING 'UTF8' falla entonces con ERROR: new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII). La salida rápida es indicar TEMPLATE template0 al crearla, la solución limpia es un sistema con configuración regional UTF-8.

Entender pg_hba.conf, la fuente de errores más frecuente

El archivo pg_hba.conf (host-based authentication) decide, antes de cualquier comprobación de contraseña, si una conexión se admite siquiera. Se lee de arriba abajo y gana la primera línea que coincide. Si no coincide ninguna, la conexión se rechaza. Una regla generosa colocada más abajo no te sirve de nada si otra más estricta actúa antes. Es con diferencia el error de configuración más habitual.

El estado de fábrica en Debian y Ubuntu tiene este aspecto:

# 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

Así está en los cuatro sistemas tratados aquí. En versiones más antiguas, por ejemplo Debian 11 con PostgreSQL 13, las dos líneas host llevan todavía md5 en lugar de scram-sha-256. El inicio de sesión por TCP funciona en ambos casos, pero ya no deberías confiar en md5.

El significado de las columnas: local representa el socket Unix, host el TCP con o sin TLS, hostssl solo las conexiones TLS. Después vienen la base de datos, el rol, el rango de red en notación CIDR y el método. Cuatro métodos son importantes. peer comprueba el usuario del sistema y solo funciona a través del socket. scram-sha-256 es el método moderno de contraseña y la elección correcta para todo lo que pase por TCP. md5 está obsoleto y no debería aparecer en configuraciones nuevas. trust deja entrar a cualquiera sin comprobación y no tiene nada que hacer en un servidor accesible.

Los mensajes de error, palabra por palabra

Saber distinguirlos de una vez te ahorra muchas conjeturas:

FATAL:  Peer authentication failed for user "appuser"

Estás conectado por el socket, pero tu usuario del sistema se llama distinto que el rol. O cambias de usuario, o te conectas con -h 127.0.0.1 para que actúe la línea host.

FATAL:  no pg_hba.conf entry for host "198.51.100.4", user "appuser", database "appdb", no encryption

El servidor está accesible, pero ninguna regla encaja con esa combinación de dirección de origen, rol y base de datos. Falta una línea, o la red indicada en la línea existente no cubre esa dirección.

FATAL:  password authentication failed for user "appuser"

La regla actúa, la contraseña no es correcta. A menudo porque el rol se creó sin LOGIN o porque la contraseña todavía procede de una instalación anterior.

psql: error: connection to server at "203.0.113.10", port 5432 failed: Connection refused

Aquí pg_hba.conf nunca entró en juego. O el servidor no está en marcha, o no escucha en esa dirección, o un firewall bloquea. Enseguida vemos más sobre esto.

Comprobar los cambios antes de recargar

PostgreSQL ofrece una vista de sistema que muestra las reglas ya interpretadas, con número de línea y errores de sintaxis. Responde a la pregunta de qué regla ve el servidor realmente, en lugar de cuál crees haber escrito:

runuser -u postgres -- psql -c "SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules;"

Los cambios en pg_hba.conf no necesitan un reinicio, basta con recargar y no se corta ninguna conexión existente:

runuser -u postgres -- psql -c "SELECT pg_reload_conf();"

Como alternativa, service postgresql reload. Un reinicio de verdad solo hace falta si has cambiado parámetros como listen_addresses, port o shared_buffers.

Abrir el acceso desde fuera

De fábrica, PostgreSQL solo escucha en localhost. Es un buen valor por defecto y solo deberías renunciar a él si de verdad es necesario. Dos cosas tienen que darse a la vez: el servidor debe escuchar en la dirección y pg_hba.conf debe permitir el origen. Si falta lo primero, obtienes Connection refused; si falta lo segundo, obtienes no pg_hba.conf entry.

La configuración está en /etc/postgresql/17/main/postgresql.conf. Debian incluye para eso la herramienta pg_conftool, que edita el archivo de forma más fiable que un buscar y reemplazar en un editor:

pg_conftool 17 main show listen_addresses
pg_conftool 17 main set listen_addresses '10.0.0.5,127.0.0.1'

Indica direcciones concretas en lugar de *. En un servidor con dirección pública e interna, así te enlazas solo a la red interna. Después añades una regla en pg_hba.conf, tan restrictiva como sea posible:

host    appdb    appuser    10.0.0.0/24    scram-sha-256

Tras un reinicio con service postgresql restart, comprueba primero en qué escucha realmente el proceso. ss -lntp | grep 5432 muestra las direcciones enlazadas. Si ahí solo aparece 127.0.0.1:5432, el cambio no ha surtido efecto, normalmente porque se refería a otro clúster o porque un archivo bajo conf.d sobrescribe el valor.

El firewall también necesita una regla, y además con indicación de origen. Un puerto 5432 abierto sin restricción en internet se escanea en cuestión de horas:

ufw allow from 10.0.0.0/24 to any port 5432 proto tcp

Un consejo honesto: en la mayoría de los casos, la mejor solución es no abrir el puerto en absoluto. Un túnel SSH con ssh -L 5432:127.0.0.1:5432 usuario@servidor basta de sobra para los accesos de mantenimiento. Para conexiones permanentes entre varios servidores, una red WireGuard es la opción más limpia, porque la base de datos sigue escuchando entonces solo en una dirección privada. Por cierto, Debian y Ubuntu activan TLS por defecto con un certificado autofirmado, por eso sslmode=require funciona de inmediato. Pero protección real frente a un atacante situado en el camino solo la ofrece sslmode=verify-full con un certificado en el que el cliente confía.

Backup con pg_dump, y la prueba de que sirve para algo

Para bases de datos sueltas, el formato custom es la mejor elección. Está comprimido, se restaura de forma selectiva y admite lectura en paralelo:

runuser -u postgres -- pg_dump -Fc -d appdb -f /var/lib/postgresql/appdb.dump

Un punto que se pasa por alto a menudo: pg_dump no guarda ni roles ni contraseñas. Esos existen a nivel de clúster y hay que respaldarlos por separado, si no, tras una restauración faltarán justo los usuarios que la aplicación necesita:

runuser -u postgres -- pg_dumpall --globals-only -f /var/lib/postgresql/globals.sql

Cuando las versiones no encajan

pg_dump: error: server version: 17.5; pg_dump version: 15.10
pg_dump: error: aborting because of server version mismatch

La regla dice: pg_dump puede ser más nuevo que el servidor, nunca más antiguo. En Debian y Ubuntu se resuelve con facilidad, porque /usr/bin/pg_dump es solo un wrapper que elige la versión de programa adecuada. Instala el paquete postgresql-client-18 y tendrás disponible la versión más reciente. Y con la extensión de Debian --cluster fuerzas el wrapper hacia un clúster concreto, aquí la versión 17, clúster main:

pg_dump --version
runuser -u postgres -- pg_dump --cluster 17/main -Fc -d appdb -f /var/lib/postgresql/appdb.dump

Mantener las contraseñas fuera del script

Para backups automáticos, la contraseña va en un .pgpass con el formato host:puerto:base:usuario:contraseña. PostgreSQL ignora el archivo sin decir nada si los permisos son demasiado amplios. Igual de importante es en qué directorio personal está, porque siempre se lee el archivo del usuario con el que el comando se ejecuta realmente. Un ~/.pgpass creado como root no surte ningún efecto mientras el backup pase por runuser -u postgres, como en este artículo. Entonces cuenta el home de postgres:

touch /var/lib/postgresql/.pgpass
chown postgres:postgres /var/lib/postgresql/.pgpass
chmod 0600 /var/lib/postgresql/.pgpass

Vacío, el archivo tampoco surte efecto. Escribe una línea por conexión, por ejemplo 127.0.0.1:5432:appdb:appuser:TuContraseñaSegura. Si en cambio tu tarea de backup se ejecuta directamente como root, sin cambio de usuario, ese mismo archivo va a /root/.pgpass.

Comprobar el backup

Un archivo de backup que nunca se ha restaurado es una suposición. La prueba dura un minuto. Primero mira el índice de contenidos, después cárgalo en una base de datos desechable y cuenta las tablas:

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

Si \dt muestra las mismas tablas que en el original, aquí al menos la tabla prueba, el backup sirve. Si en cambio el comando responde Did not find any relations., la base de datos respaldada estaba vacía y la prueba no demuestra nada. En appdb retiras luego la tabla de prueba con runuser -u postgres -- psql -d appdb -c "DROP TABLE prueba;". Para el día a día basta una entrada en /etc/cron.d que deje los dos archivos con la fecha en el nombre y limpie los antiguos. Lo importante es que los archivos salgan después del servidor. Un backup en el mismo disco protege frente a un DROP TABLE accidental, no frente a un fallo del hardware.

Cuando el clúster no arranca

Si el servicio no arranca, el estado del servicio suele decirte solo que algo ha fallado. La causa real está en el log del clúster:

tail -n 30 /var/log/postgresql/postgresql-*-main.log

Hay una línea que puedes pasar por alto tranquilamente. El mensaje FATAL: role "root" does not exist, ya conocido de la primera sección, procede casi siempre de pg_isready: la herramienta construye su intento de conexión con el usuario del sistema con el que has iniciado sesión, es decir root, y el servidor registra ese rol desconocido. El valor de retorno sigue siendo 0, la salida dice accepting connections y el clúster está perfectamente.

En sistemas con systemd, journalctl -u postgresql@17-main --no-pager -n 50 entrega las mismas líneas. Fíjate en la unidad que lleva el número de versión: postgresql.service es solo una envoltura que arranca todos los clústeres, y también informa de éxito cuando un clúster concreto ha fallado. Por eso pg_lsclusters es el control más fiable.

Tres mensajes cubren la mayoría de los casos. could not bind IPv4 address "0.0.0.0": Address already in use significa que otro clúster ocupa el puerto, mira la sección sobre los dos clústeres. Un mensaje sobre No space left on device al escribir el postmaster.pid quiere decir sencillamente disco lleno, algo que confirmas con df -h. Y los errores por permisos inválidos en el directorio de datos aparecen tras ejecutar chmod o chown sin cuidado: /var/lib/postgresql/17/main debe pertenecer al usuario postgres y llevar el modo 0700.

Para terminar, una nota sobre la operación diaria: en su configuración básica, PostgreSQL trabaja de forma conservadora y ni de lejos aprovecha toda la RAM de un servidor. Antes de tocar shared_buffers y work_mem, activa pg_stat_statements del paquete contrib y mira qué consultas cuestan tiempo de verdad. En la práctica, el cuello de botella está casi siempre en un índice que falta, no en los parámetros de memoria.

Preguntas frecuentes

¿Qué versión de PostgreSQL obtengo en mi distribución?
Desde el repositorio de la distribución, Debian 13 entrega la versión 17, Debian 12 la versión 15, Ubuntu 24.04 la versión 16 y Ubuntu 22.04 la versión 14. Esa asignación está ligada al release correspondiente y ya no cambia durante su vida útil. Si necesitas otra versión mayor, integra el repositorio oficial PGDG en apt.postgresql.org, que soporta trixie, bookworm, noble y jammy.
¿Por qué al arrancar psql aparece el mensaje "role root does not exist"?
Debian y Ubuntu usan el método peer para las conexiones locales por socket. PostgreSQL compara entonces el usuario del sistema con el nombre del rol, y no existe ningún rol llamado root. Cambia al usuario del sistema postgres con su - postgres, o ejecuta comandos sueltos con runuser -u postgres -- psql, que con sudo sería sudo -u postgres psql.
¿Qué significa "no pg_hba.conf entry for host" y cómo lo soluciono?
El servidor está accesible, pero ninguna línea de pg_hba.conf encaja con la combinación de dirección de origen, rol y base de datos. Añade una línea host con la red CIDR adecuada y el método scram-sha-256. Como gana la primera línea que coincide, debe ir antes de cualquier rechazo más general. Comprueba el resultado con una consulta a la vista pg_hba_file_rules y recarga la configuración con SELECT pg_reload_conf().
¿Por qué mi usuario no puede crear tablas aunque tenga permiso para usar la base de datos?
A partir de PostgreSQL 15 ya no todos los usuarios pueden escribir en el esquema public, y el error dice "permission denied for schema public". Afecta a Debian 12, Debian 13 y Ubuntu 24.04. Lo más limpio es crear la base de datos directamente con CREATE DATABASE appdb OWNER appuser, porque el esquema public pertenece al rol pg_database_owner. A posteriori ayuda GRANT ALL ON SCHEMA public TO appuser, ejecutado en la base de datos afectada.
¿Tengo que reiniciar PostgreSQL después de cambiar pg_hba.conf?
No, basta con recargar y no se corta ninguna conexión existente. Se hace con SELECT pg_reload_conf() o con service postgresql reload. Un reinicio de verdad solo hace falta con parámetros que se leen al arrancar, como listen_addresses, port o shared_buffers.
¿Basta pg_dump como backup completo?
No. pg_dump respalda una sola base de datos, pero no los roles ni las contraseñas, porque se guardan a nivel de clúster. Añade por eso pg_dumpall --globals-only. Y comprueba el backup cargándolo con pg_restore en una base de datos desechable y comparando las tablas con \dt. Para eso la base de datos respaldada tiene que contener tablas, si no \dt solo responde "Did not find any relations." y la prueba no demuestra nada. Un backup que nunca se ha restaurado es solo una suposición.

PostgreSQL Debian Ubuntu Base de datos pg_hba.conf pg_dump Linux Administración de servidores