---
title: "Address already in use: quién tiene el puerto y por qué kill -9 va al final"
description: "Cómo encontrar el proceso con `ss`, ver quién lo levantó y cortarlo sin `kill -9`. Y qué significa que esté escuchando en `0.0.0.0`."
canonical: "https://vtsecurity.com.ar/articulo/address-already-in-use"
author: "Valentín Torassa"
lang: "es-AR"
datePublished: "2026-09-25T15:58:44.932Z"
dateModified: "2026-09-25T15:58:44.932Z"
---

# Address already in use: quién tiene el puerto y por qué kill -9 va al final

> Cómo encontrar el proceso con `ss`, ver quién lo levantó y cortarlo sin `kill -9`. Y qué significa que esté escuchando en `0.0.0.0`.

Pasa así: levantás tu app, la terminal te devuelve `EADDRINUSE` y no arranca. Buscás el error y la primera respuesta dice `kill -9 $(lsof -t -i:3000)`. Lo corrés y anda.

Casi siempre. A veces el puerto vuelve a estar ocupado un segundo después. Otras, lo que mataste era la base de otro proyecto que tenías abierto. Y en el camino se pasa por alto algo que importa más que el error: ese proceso que no sabías que seguía corriendo también podía estar atendiendo a otras máquinas.

## Quién tiene el puerto

El error solo dice el puerto. Para saber quién lo tiene está `ss`, que viene en cualquier distro actual:

```bash
$ node -e "require('http').createServer().listen(3000)"
Error: listen EADDRINUSE: address already in use :::3000
$ ss -ltnp 'sport = :3000'
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      5            0.0.0.0:3000      0.0.0.0:*    users:(("python3",pid=3365731,fd=3))
```

`-l` muestra lo que está escuchando, `-t` TCP, `-n` números en vez de nombres y `-p` el proceso. La última columna es la respuesta: un `python3` con PID 3365731. Si esa columna sale vacía, el proceso es de otro usuario y con `sudo` adelante aparece.

Con el PID, `ps` te dice qué es y hace cuánto corre:

```bash
$ ps -o pid,ppid,user,etime,cmd -p 3365731
    PID    PPID USER         ELAPSED CMD
3365731 3365724 valen          00:01 python3 -m http.server 3000
```

Acá dice un segundo porque lo levanté para el ejemplo; uno olvidado suele decir días. `python3 -m http.server` es un clásico: lo usaste para pasar un archivo y quedó corriendo en otra terminal, sirviendo la carpeta entera donde lo levantaste, archivos ocultos incluidos.

> *En macOS `ss` no existe.* `lsof -i :3000` te da lo mismo, y en Linux también anda.

## Qué quiere decir `0.0.0.0`

Volvé a la columna `Local Address`. `0.0.0.0:3000` quiere decir que el proceso acepta conexiones por cualquier interfaz de la máquina: le puede hablar cualquiera que esté en tu red. Mandá pedidos y cambiá la dirección mientras llegan.

*Red de ejemplo. El router corta lo que entra de internet mientras nadie le abra el puerto.*

Lo probé con ese mismo servidor, levantado en una carpeta de prueba con un `.env`. Desde otra máquina de la red:

```bash
$ curl -s http://<ip>:3000/.env
OPENAI_API_KEY=sk-proj-demo-no-es-real
```

La key es de mentira y `<ip>` reemplaza la de mi máquina. Levantado con `--bind 127.0.0.1`, el mismo curl devuelve `Couldn't connect to server`. Y si lo corrés en tu home, la carpeta que se sirve incluye `.ssh`.

El error de Node de más arriba también lo dice: `:::3000`. Si no le pasás una dirección, `listen(3000)` escucha en `::`, que son todas.

> *Un firewall o el router pueden cortar la conexión antes.* En una red que no es tuya, no contaría con eso.

## `kill` manda una señal

`kill` no mata: le manda una señal al proceso. Si no le decís cuál, manda `TERM`, que le pide terminar y lo deja cerrar lo que tiene abierto. `kill -9` manda `KILL`, que el programa no puede atender: el kernel lo saca en el acto. Mandá pedidos y, cuando quieras, mandale una señal. Después levantalo de nuevo y probá la otra.

*Programa y tiempos de ejemplo. No todos dejan un lock, pero cualquiera pierde lo que no alcanzó a escribir.*

| Señal | Número | Qué pide | ¿La puede atender el proceso? |
| - | - | - | - |
| `HUP` | 1 | Varios servicios la usan para releer la configuración | Sí |
| `INT` | 2 | Es lo que manda Ctrl+C | Sí |
| `TERM` | 15 | Que termine: cerrar lo que tiene abierto y salir | Sí |
| `KILL` | 9 | Nada. El kernel lo saca en el momento | No |

El orden es `kill`, esperar unos segundos, y `kill -9` solo si sigue ahí.

## Si vuelve solo, es un servicio

A veces matás el proceso y el puerto vuelve a estar ocupado al segundo. Lo reproduje con un servicio de systemd que se reinicia solo, y pasó exactamente eso. Mandá pedidos, matalo y mirá qué pasa con los que llegan mientras no está.

*Los dos primeros PID son los de la prueba real; los que siguen, de ejemplo.*

El padre de ese proceso es systemd, así que matarlo no sirve. `systemctl status` acepta un PID y te dice de qué servicio es:

```bash
$ systemctl --user status 3366835 | head -4
● demo-web.service - [systemd-run] /usr/bin/python3 -m http.server 3000 --bind 127.0.0.1
     Loaded: loaded (/run/user/1000/systemd/transient/demo-web.service; transient)
  Transient: yes
     Active: active (running) since Fri 2026-09-25 11:21:28 -03; 1s ago
```

Con eso sabés qué parar: `systemctl --user stop demo-web`. En un servidor lo normal es un servicio del sistema, y va sin `--user`. `systemctl disable` hace que no vuelva a arrancar con la máquina.

> *Si en la columna del proceso dice `docker-proxy`*, el puerto lo publicó un contenedor. `docker ps` te dice cuál, y se para con `docker stop`.

## El criterio

Antes de matar un proceso, fijate qué es y quién lo levantó: `ss -ltnp` y `ps` te lo dicen en dos líneas. Si vuelve solo, es un servicio y se para con `systemctl stop`.

Y mirá la dirección en la que escucha. Si dice `0.0.0.0` y no sabés por qué, arreglá eso antes que el error.
