Guía
Puerto 5432 de PostgreSQL ocupado: el caso donde matar el proceso no sirve
14 de septiembre de 20264 min de lectura
El puerto 5432 es un caso especial, y vale la pena entender por qué antes de empezar a matar cosas.
Con un servidor de desarrollo, tú levantaste el proceso, así que matarlo termina la historia. A Postgres normalmente lo levanta otra cosa: el gestor de servicios de Homebrew, Docker, o Postgres.app. Matas el proceso y el gestor lo vuelve a levantar, a veces en segundos, lo que hace parecer que el kill falló en silencio.
Entonces la primera pregunta no es cuál es el PID, es quién está a cargo de esto.
Averigua quién es dueño del 5432
lsof -i :5432
El nombre del comando en la salida te dice en qué caso estás:
postgresy estás en un Mac con Homebrew, casi seguro es un servicio de brew.com.dockeodocker-proxy, es un contenedor.postgrescon Postgres.app instalado, es esa app.
Ajusta el arreglo al dueño. Ese es todo el artículo.
Homebrew
Si Homebrew lo levantó, Homebrew debería detenerlo:
brew services list
brew services stop postgresql@16
Usa el nombre exacto que imprime brew services list, el sufijo de versión importa.
Matar el PID acá es la tarde perdida clásica. brew services registra un trabajo en launchd, y el propósito completo de launchd es mantener eso corriendo. Lo matas, launchd lo reinicia, el puerto vuelve a estar ocupado, y parece que no pasó nada.
Docker
docker ps --filter "publish=5432"
docker stop <contenedor>
La misma lógica. Matar docker-proxy no detiene el contenedor, y Docker va a volver a publicar el puerto. Las políticas de reinicio lo empeoran: un contenedor con always o unless-stopped vuelve después de que lo mates y después de que reinicies.
Si es parte de un proyecto de Compose, docker compose down en el directorio de ese proyecto es más limpio que detener contenedores uno por uno.
Postgres.app
Deténlo desde su ícono en la barra de menú. No hay razón para hacer esto desde una terminal.
El caso del postmaster.pid obsoleto
Síntoma distinto, mismo puerto. Postgres se niega a partir y dice algo como:
FATAL: lock file "postmaster.pid" already exists
HINT: Is another postmaster (PID 12345) running in data directory ...?
Esto es Postgres protegiendo su directorio de datos, no un conflicto de puerto. Escribe postmaster.pid al arrancar y lo borra en un apagado limpio. Un kill duro o un corte de luz lo dejan ahí.
Revisa si ese PID es real antes de tocar nada:
ps -p 12345
Si no vuelve nada, el archivo está obsoleto y borrarlo es seguro. Si sí aparece un proceso, deténlo como corresponde y no borres el archivo. Borrar un archivo de bloqueo vivo invita a que dos postmaster usen el mismo directorio de datos, que es un día genuinamente malo.
Cuándo sí corresponde matar el proceso
Si levantaste Postgres a mano, desde una terminal, y no por un gestor de servicios, entonces terminarlo normalmente es lo correcto:
lsof -ti :5432 | xargs kill
Un kill normal manda SIGTERM, que Postgres trata como apagado inteligente y maneja bien. Evita kill -9 en una base de datos si tienes cualquier alternativa. Un apagado sucio significa recuperación en el próximo arranque, y en el peor caso es así como apareció el archivo pid obsoleto en primer lugar.
Correr dos versiones de Postgres
Una causa común acá es actualizar sin detener la versión vieja. Las dos quieren el 5432 y la segunda pierde. O detienes la que no estás usando, o pones la segunda en otro puerto en su postgresql.conf:
port = 5433
Y te conectas con -p 5433. Vale la pena hacerlo a propósito cuando mantienes una versión antigua para un proyecto heredado.
La lección general
El dueño importa más que el PID. Homebrew, Docker y launchd existen para reiniciar lo que tú mates, y pelear contra ellos con kill es una pelea que pierdes repetida y confusamente.
Relacionado: qué significa realmente EADDRINUSE.
Bosun muestra qué está ocupando cada puerto en tu barra de menú y nombra los contenedores de Docker como corresponde en vez de mostrar docker-proxy, así puedes ver en qué caso estás antes de decidir qué hacer. macOS 14 o posterior, prueba de 14 días.
Ve esto en vez de escribirlo
Bosun vive en tu barra de menú y muestra cada puerto abierto en tu Mac, en vivo, mapeado al proceso detrás. Un clic para matarlo, SIGTERM primero. Útil la primera vez que pasa esto. Realmente útil la quinta vez que pasa en una misma tarde.