Linux では sudo ss -ltnp 'sport = :8000' で、8000番ポートで待ち受けているプロセスの名前と PID が分かります。 lsof・netstat・fuser でも同じことが分かり、出す情報と得意なことが少しずつ違います。

sudo ss -ltnp 'sport = :8000'            # Linux(標準で入っていることが多い)
sudo lsof -nP -iTCP:8000 -sTCP:LISTEN    # Linux・Mac
netstat -ano | findstr :8000             # Windows(コマンドプロンプト)

8000番で動かした Python のサーバーに対して、4つのコマンドを実際に動かした結果です。

コマンド 分かること 出力(抜粋) 入っているか
ss -ltnp 状態・待ち受けアドレス・プロセス名・PID・fd 0.0.0.0:8000 ... users:(("python3",pid=1869,fd=3)) iproute2 に含まれる
lsof -i :8000 プロセス名・PID・ユーザー・IPv4/IPv6 python3 1869 root 3u IPv4 ... TCP *:8000 (LISTEN) 別に入れることがある
netstat -ltnp 状態・アドレス・PID/プロセス名 0.0.0.0:8000 ... LISTEN 1869/python3 net-tools(入っていないことが多い)
fuser -v 8000/tcp PID・ユーザー・プロセス名。-k で止める 8000/tcp: root 1869 F.... python3 psmisc

確認環境:Ubuntu 24.04(Linux カーネル 6.18)で、ss(iproute2-6.1.0)・lsof 4.95.0・netstat(net-tools 2.10)・fuser(PSmisc 23.7)を動かし、Python 3.11・Node.js 22.22.2・Java(OpenJDK 21.0.10)でエラー文と TIME_WAIT の動きを再現しました。Mac・Windows・Docker のコマンドは公式ドキュメントで確かめています。図は mermaid-cli 11.14.0 で描画できることを確かめました(確認日 2026年10月13日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ポートを使っているプロセスの調べ方|ss・lsof・netstat比較」

切り分けの流れ

「Address already in use」が出たときは、まず「待ち受けているプロセスがいるか」を見て、いなければ TIME_WAIT やアドレスの指定を疑います。

flowchart TD
    A["Address already in use / EADDRINUSE"] --> B{"sudo ss -ltnp で<br/>そのポートが LISTEN か"}
    B -- "いる" --> C{"プロセス名・PID は出たか"}
    C -- "出た" --> D["ps で中身を確かめて止める<br/>(kill・systemctl stop)"]
    C -- "出ない" --> E["sudo を付ける / コンテナ・別ユーザーを疑う"]
    B -- "いない" --> F{"ss -tan state time-wait に<br/>そのポートがあるか"}
    F -- "ある" --> G["TIME_WAIT:待つか SO_REUSEADDR"]
    F -- "ない" --> H["待ち受けアドレスの指定・<br/>同じプロセスの二重 listen を疑う"]

ss:Linux で最初に使うコマンド

ss は iproute2 に含まれ、多くの Linux ディストリビューションに最初から入っています。 netstat の後継として使われています。

$ sudo ss -ltnp 'sport = :8000'
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      5            0.0.0.0:8000      0.0.0.0:*    users:(("python3",pid=1869,fd=3))
オプション 意味(man ss より)
-l 待ち受け中(LISTEN)のソケットだけ
-t / -u TCP / UDP
-n サービス名に変換しない(:http ではなく :80)
-p ソケットを使っているプロセスを出す
-a 待ち受け中と接続中の両方
-s 集計だけ(件数が多いとき向き)

出力の読み方

列 例 読み方
State LISTEN 待ち受け中。接続中なら ESTAB
Local Address:Port 0.0.0.0:8000 どのアドレスで待っているか。0.0.0.0 は全部、127.0.0.1 は自分のマシンからだけ
Peer Address:Port 0.0.0.0:* 相手。待ち受け中は *
Process ("python3",pid=1869,fd=3) プロセス名・PID・ファイル記述子の番号
Recv-Q / Send-Q 0 / 5 LISTEN では、Send-Q は受け付け待ちの列の上限(この例は 5)

'sport = :8000' はフィルタの書き方です。 grep :8000 だと :80001 や相手側のポートも引っかかりますが、フィルタなら自分側のポートだけに絞れます。相手側のポートは dport、両方なら '( sport = :8000 or dport = :8000 )' と書きます。

sudo を付けないとプロセス名が出ない

自分以外のユーザーのプロセスは、root でないとプロセス名が出ません。 root で動くサーバーを、一般ユーザー(nobody)から調べた結果です。

コマンド(一般ユーザー) 結果
ss -ltnp 'sport = :8000' 行は出るが、Process 列が空
lsof -i :8000 何も出ない(終了ステータス 1)
netstat -ltnp PID 列が -、先頭に (Not all processes could be identified, ...)

lsof は、見えないと何も出しません。 「何も出ないから空いている」と判断すると間違えるので、ss -ltn(-p なし)で、ポートが使われているかどうかを先に見ます。

lsof:ユーザー名と接続の向きが分かる

$ sudo lsof -nP -iTCP:8000 -sTCP:LISTEN
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
python3 1869 root    3u  IPv4  22948      0t0  TCP *:8000 (LISTEN)
オプション 意味
-i :8000 8000番を使うネットワークのファイル(待ち受け・接続中の両方)
-iTCP:8000 -sTCP:LISTEN TCP の 8000番で、待ち受け中のものだけ
-n / -P ホスト名・ポート名に変換しない(速くなる)
-t PID だけを出す(kill $(lsof -t -i :8000) のように使う)

-i :8000 だけだと、接続中のクライアントも出ます。 8000番に1本つないだ状態で動かした結果です。サーバー(PID 3064)の待ち受けと接続、クライアント(PID 3066)の接続が並びます。

$ sudo lsof -nP -i :8000
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
python3 3064 root    3u  IPv4  29377      0t0  TCP *:8000 (LISTEN)
python3 3064 root    4u  IPv4  28632      0t0  TCP 127.0.0.1:8000->127.0.0.1:37732 (ESTABLISHED)
python3 3066 root    3u  IPv4  28631      0t0  TCP 127.0.0.1:37732->127.0.0.1:8000 (ESTABLISHED)

NAME の -> の左が自分、右が相手です。止めたいのは LISTEN の行のプロセスで、クライアント側の PID を止めても、ポートは空きません。

netstat と fuser

$ sudo netstat -ltnp | grep :8000
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      1869/python3

$ sudo fuser -v 8000/tcp
                     USER        PID ACCESS COMMAND
8000/tcp:            root       1869 F.... python3

netstat は net-tools に含まれ、最近のディストリビューションでは最初から入っていないことがあります。fuser は -k を付けると、そのポートを使うプロセスにシグナル(既定は SIGKILL)を送ります。 手元では sudo fuser -k 8001/tcp で、8001番のプロセスが止まりました。中身を確かめずに止めることになるので、先に -v で何が止まるかを見ます。

見つけたプロセスを確かめて止める

PID が分かったら、止める前に「何のプロセスか」を確かめます。 同じ python3 や java でも、別の人が動かしているサービスのことがあります。

$ ps -o pid,ppid,user,lstart,cmd -p 1869
  PID  PPID USER                      STARTED CMD
 1869     1 root     Tue Oct 13 00:35:45 2026 python3 -m http.server 8000 --bind 0.0.0.0

$ ls -l /proc/1869/cwd
lrwxrwxrwx 1 root root 0 Oct 13 00:35 /proc/1869/cwd -> /home/you/app
確かめること コマンド 分かること
起動したコマンド ps -o cmd -p PID 引数まで(どの設定ファイル・ポートか)
親のプロセス ps -o ppid -p PID PPID が 1 なら、サービスや nohup で切り離されたもの
作業ディレクトリ ls -l /proc/PID/cwd どのプロジェクトから起動したか
サービスか systemctl status PID systemd のサービス名
止め方 コマンド 向いている場面
普通に止める kill PID(SIGTERM) まずこれ。後片付けをしてから終わる
強制的に止める kill -9 PID SIGTERM で止まらないとき
サービスを止める sudo systemctl stop 名前 systemd が動かしているもの(kill しても再起動される)
ポート指定で止める sudo fuser -k 8000/tcp 中身を確かめたあと

プロセスの調べ方と止め方は、関連記事「Linuxプロセス確認と停止|ps・top・kill逆引きコマンド一覧」で扱っています。

Mac で調べる

Mac でも lsof が使えます。 lsof のマニュアルは Mac(Darwin)を含む複数の UNIX を対象にしていて、-iTCP:8000 -sTCP:LISTEN・-t・-n・-P の書き方は Linux と同じです。

sudo lsof -nP -iTCP:8000 -sTCP:LISTEN
kill $(lsof -t -iTCP:8000 -sTCP:LISTEN)

マニュアルには「Apple Darwin は UDP の状態を lsof に渡さない」とあり、Mac では UDP を状態で絞り込めません。UDP は sudo lsof -nP -iUDP:53 のように状態を付けずに調べます。

Windows で調べる

コマンドプロンプトでは netstat -ano、PowerShell では Get-NetTCPConnection を使います。

netstat -ano | findstr :8000
tasklist /FI "PID eq 1234"
taskkill /PID 1234 /F
Get-NetTCPConnection -LocalPort 8000 -State Listen |
  Select-Object LocalAddress, LocalPort, State, OwningProcess
Get-Process -Id (Get-NetTCPConnection -LocalPort 8000 -State Listen).OwningProcess
Stop-Process -Id 1234
コマンド オプションの意味(Microsoft のドキュメントより)
netstat -a すべての TCP 接続と、待ち受け中の TCP・UDP ポート
netstat -n アドレスとポートを数字で出す(名前に変換しない)
netstat -o 接続ごとに PID を出す
netstat -b 実行ファイル名を出す(権限が足りないと失敗する)
Get-NetTCPConnection -LocalPort ローカルのポートで絞り込む。-State には Listen・Established・TimeWait など

Get-NetTCPConnection の結果の OwningProcess が PID です。

Docker のコンテナが使っている場合

ホストのポートをコンテナに割り当てている(-p 8080:80)と、ホスト側では Docker が待ち受けます。 ss で見ると、プロセス名がアプリではなく Docker 側のプロセス(docker-proxy など)になることがあります。Docker のドキュメントでは、ユーザーランドプロキシは既定で有効(--userland-proxy=true)です。

docker ps --format 'table {{.ID}}\t{{.Names}}\t{{.Ports}}'
docker port コンテナ名          # そのコンテナのポートの割り当て
docker stop コンテナ名
見るところ 例 読み方
docker ps の PORTS 列 0.0.0.0:32768->80/tcp 左がホスト側、右がコンテナ側。この例はホストの 32768番を使う
docker ps --filter publish=80 ― ドキュメントの例では、コンテナ側が 80番のコンテナが出る
docker ps -a Exited 止まったコンテナはポートを使わない

docker ps --filter publish= はコンテナ側のポートで絞り込みます。 ホスト側の 8080番を使うコンテナを探すときは、PORTS 列を見ます。Docker の「port is already allocated」のエラーは、関連記事「Docker port is already allocatedの直し方」で扱っています。

言語ごとのエラー文

同じ 8000番が使われているときに、それぞれ出たエラーです。

言語 エラー文
Python 3.11 OSError: [Errno 98] Address already in use
Node.js 22 Error: listen EADDRINUSE: address already in use 0.0.0.0:8000(code: 'EADDRINUSE', errno: -98)
Java 21 java.net.BindException: Address already in use
Error: listen EADDRINUSE: address already in use 0.0.0.0:8000
    at Server.setupListenHandle [as _listen2] (node:net:1940:16)
    ...
  code: 'EADDRINUSE',
  errno: -98,
  syscall: 'listen',
  address: '0.0.0.0',
  port: 8000

98 は Linux の EADDRINUSE の番号です。 どの言語でも、OS の bind(ポートの割り当て)が失敗したことを表しています。言語ごとの直し方は、関連記事「EADDRINUSE: address already in useの直し方」「Port 8080 was already in useの直し方|OS別の手順」で、OS 別の手順のまとめは「Address already in useの解決方法【Windows・Mac・Linux】」で扱っています。

待ち受けアドレスが違っても、ぶつかる

127.0.0.1:8000 と 0.0.0.0:8000 は、別のアドレスでも同時には待ち受けられません。 Python で試した結果です。

先に待ち受けたもの 後から bind したもの 結果
127.0.0.1:9000 0.0.0.0:9000 [Errno 98] Address already in use
127.0.0.1:9000 0.0.0.0:9000(SO_REUSEADDR あり) [Errno 98] Address already in use
0.0.0.0:8000 127.0.0.1:8000 [Errno 98] Address already in use

0.0.0.0 は「全部のアドレス」なので、127.0.0.1 の同じポートと重なります。ss の Local Address が 127.0.0.1:9000 になっていて「8000 しか見ていなかった」と見落とすことがあるので、ポート番号で絞り込んで見ます。

TIME_WAIT と SO_REUSEADDR

サーバーを止めた直後に起動し直すと、待ち受けているプロセスがいないのに「Address already in use」になることがあります。 原因は、閉じた接続が TIME_WAIT(閉じたあと、遅れて届くパケットに備えてしばらく残る状態)でポートを持っているためです。

$ ss -tan state time-wait '( sport = :9100 )'
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0      0          127.0.0.1:9100    127.0.0.1:57052

TIME_WAIT は、先に接続を閉じた側に残ります。 サーバーが接続を先に閉じると、サーバーのポートに残ります。

再現:両方に SO_REUSEADDR が要る

サーバーが接続を先に閉じて TIME_WAIT を作り、そのあと同じポートで新しいサーバーを bind しました。

前のサーバー 新しいサーバー 結果
SO_REUSEADDR なし なし Address already in use
なし あり Address already in use
あり なし Address already in use
あり あり OK

Linux では、前のソケットと新しいソケットの両方に SO_REUSEADDR が付いていないと、TIME_WAIT のポートを使えませんでした。 man socket(7) にも、Linux では両方のソケットに設定が要ると書かれています。SO_REUSEADDR を付けても、待ち受け中(LISTEN)のソケットがいるときは使えません(上の表の2行目のとおり)。

付けないままでも、時間がたつと空きます。手元では、61秒待つと SO_REUSEADDR なしで bind できました。

主なサーバーの設定

言語・ライブラリ SO_REUSEADDR 確かめ方
Python http.server.HTTPServer 付く(allow_reuse_address = 1) 手元で属性を表示
Python socketserver.TCPServer 付かない(False) 同上。allow_reuse_address = True にすると付く
Java ServerSocket(Linux) 付く(getReuseAddress() が true) 手元で表示
Node.js ドキュメントでは net.Socket に設定 Node.js のドキュメント

自分で socket を作るときは、bind の前に設定します。

import socket
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)   # bind の前に
s.bind(("0.0.0.0", 8000))
s.listen()

SO_REUSEPORT は別物です。 同じポートを複数のソケットで同時に待ち受け、OS が接続を振り分けるためのもので、Linux 3.9 から使えます。設定はすべてのソケットに要り、同じ実効ユーザーのプロセスどうしに限られます(man socket(7) より)。「ポートが空かない」ときに付けるものではありません。

よくある質問

Q. ss でも lsof でも何も出ないのに Address already in use になります。 A. 次の順に見ます。① sudo を付けたか(付けないと他のユーザーのプロセスは見えない)、② ss -tan state time-wait に残っていないか、③ 同じプログラムの中で2回 listen していないか(設定の読み込みが2回など)、④ コンテナや別のネットワーク名前空間の中ではないか。

Q. kill したのに、すぐ同じポートでプロセスが立ち上がります。 A. systemd・supervisor・Docker の再起動設定などが、止まったプロセスを起動し直しています。PPID と systemctl status PID で親を確かめ、サービスとして止めます。

Q. UDP のポートを調べるには? A. sudo ss -lunp 'sport = :53'、sudo lsof -nP -iUDP:53 のように、-u・-iUDP に変えます。

Q. どのポートが何に使われるのかを知りたいです。 A. 関連記事「ポート番号一覧【2026年版】well-knownポートと確認コマンドの早見表」で扱っています。

Q. ss や lsof が無いと言われます。 A. Ubuntu なら ss は iproute2、lsof は lsof、netstat は net-tools、fuser は psmisc のパッケージで入ります。コマンドが見つからないときの調べ方は、関連記事「command not foundの直し方|PATHの確認方法と原因別の対処表」で扱っています。

まとめ

  • Linux は sudo ss -ltnp 'sport = :ポート'、Mac は sudo lsof -nP -iTCP:ポート -sTCP:LISTEN、Windows は netstat -ano か Get-NetTCPConnection
  • sudo を付けないと、他のユーザーのプロセスは見えない(lsof は何も出さない)
  • 止める前に ps・/proc/PID/cwd・systemctl status で何のプロセスかを確かめる
  • Docker は PORTS 列の左がホスト側
  • 127.0.0.1 と 0.0.0.0 の同じポートもぶつかる
  • 待ち受けがいないのに使えないときは TIME_WAIT。Linux では前と新しいソケットの両方に SO_REUSEADDR が要った

参考・出典

確認日はいずれも 2026年10月13日です。

  • ss(8) — Linux manual page:https://man7.org/linux/man-pages/man8/ss.8.html
  • socket(7) — Linux manual page(SO_REUSEADDR・SO_REUSEPORT):https://man7.org/linux/man-pages/man7/socket.7.html
  • lsof(8) — Linux manual page:https://man7.org/linux/man-pages/man8/lsof.8.html
  • Microsoft Learn「netstat」:https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/netstat
  • Microsoft Learn「Get-NetTCPConnection」:https://learn.microsoft.com/en-us/powershell/module/nettcpip/get-nettcpconnection
  • Docker Docs「docker container ls」:https://docs.docker.com/reference/cli/docker/container/ls/
  • Docker Docs「docker container port」:https://docs.docker.com/reference/cli/docker/container/port/
  • Docker Docs「Port publishing and mapping」:https://docs.docker.com/engine/network/port-publishing/
  • Node.js ドキュメント「Net」(EADDRINUSE・reusePort):https://nodejs.org/api/net.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ポートを使っているプロセスの調べ方|ss・lsof・netstat比較」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?