Puerto 3000 en uso en Mac: cómo encontrarlo y liberarlo
¿Ves EADDRINUSE en el puerto 3000? Aprende a identificar qué proceso lo ocupa y cómo terminarlo, con o sin Terminal.
Inicias tu servidor de desarrollo y de inmediato aparece esto:
Error: listen EADDRINUSE: address already in use :::3000
No cambiaste nada. No abriste otro servidor. Aun así, algo está bloqueando el puerto 3000.
Por qué ocurre esto
Los conflictos de puertos casi siempre provienen de un proceso que falló o se cerró a la fuerza sin liberar su socket. Cuando un proceso termina de forma abrupta, el kernel de macOS mantiene el puerto ocupado hasta que el proceso desaparece por completo o se termina de manera explícita. El socket queda abierto aunque nada esté escuchando activamente en él.
Esto ocurre con frecuencia en servidores Node, aplicaciones Rails y otros frameworks de desarrollo que usan el puerto 3000 por defecto. Cierras la ventana de Terminal, el proceso queda en un estado intermedio, y la próxima vez que intentas iniciar un servidor nuevo choca con el binding anterior.
Cómo encontrar el proceso
El comando lsof (list open files) muestra qué proceso está usando un puerto. Ejecuta esto en Terminal:
lsof -i :3000
Verás una salida similar a esta:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 8412 aaron 23u IPv6 0x1234abcd5678 0t0 TCP *:3000 (LISTEN)
Esto es lo que significa cada columna:
- COMMAND: el nombre del ejecutable que tiene el puerto
- PID: el identificador del proceso que usarás para terminarlo
- USER: la cuenta que ejecuta el proceso
- FD: el descriptor de archivo (el sufijo
uindica lectura y escritura) - TYPE:
IPv4oIPv6 - NODE: el protocolo (
TCPen este caso) - NAME: el puerto y su estado (
LISTENsignifica que está activamente ocupado)
La columna PID es la que necesitas para el siguiente paso.
Cómo terminarlo
Una vez que tienes el PID, envíale SIGKILL:
kill -9 8412
El flag -9 envía SIGKILL, lo que fuerza al proceso a terminar de inmediato. A diferencia de SIGTERM (señal 15), SIGKILL no puede ser capturada ni ignorada por el proceso. Termina sin ninguna limpieza, que es exactamente lo que necesitas cuando un proceso ya está bloqueado.
Si quieres hacerlo en una sola línea sin buscar el PID manualmente:
kill -9 $(lsof -ti :3000)
El flag -t le indica a lsof que muestre solo el PID, sin encabezados de columnas. Eso lo hace seguro para pasar directamente a kill.
Cuando lsof no muestra nada
Si lsof -i :3000 no devuelve nada pero sigues viendo EADDRINUSE, es probable que el puerto esté en estado TIME_WAIT. Este es un período de espera que el sistema operativo aplica después de que un socket se cierra normalmente. El kernel retiene el puerto durante un breve intervalo (típicamente entre 30 y 60 segundos) para manejar paquetes tardíos de conexiones anteriores.
En este caso no hay nada que terminar porque no existe ningún proceso. Espera un minuto e intenta de nuevo, o apunta tu servidor a un puerto diferente mientras se completa el período de espera.
Otros puertos de desarrollo comunes
Los mismos comandos lsof y kill funcionan con cualquier puerto. Algunos de los más frecuentes en desarrollo:
- 5000: Python Flask, Rails antiguo
- 8080: contenedores de servlets Java, muchos proxies
- 8000: Django, servidores HTTP de Python
- 5173: Vite
- 4200: Angular CLI
Solo cambia el número de puerto en lsof -i :PUERTO y kill -9 $(lsof -ti :PUERTO).
Usar Portie
Si prefieres no memorizar flags, Portie muestra cada puerto abierto en tu Mac junto con el proceso que lo tiene, con actualización automática cada 3 segundos. La lista en vivo es gratuita. Puedes ver de un vistazo qué está usando el puerto 3000 y qué aplicación lo controla.
La compra única de $8.99 agrega la posibilidad de terminar un proceso directamente desde la lista, con SIGTERM o SIGKILL, sin abrir Terminal. Si pasas tiempo en desarrollo local, el flujo de dos segundos para terminar procesos desde la lista vale la pena rápidamente.