「EADDRINUSE: address already in use」エラーの原因と解決方法

「EADDRINUSE: address already in use」エラーの原因と解決方法

Error: listen EADDRINUSE: address already in use :::3000

Node.js や各種サーバーを起動しようとしたときに突然このエラーが出て起動できない——よくある状況です。原因はシンプルですが、「どのプロセスが使っているのか」「どうやって解放するか」 で手が止まりやすいのがこのエラーの特徴です。

本記事では以下の疑問に答えます。

  • EADDRINUSE とはどういう意味か
  • 使用中のポートとプロセスをどうやって特定するか
  • プロセスを終了してポートを解放する方法
  • Node.js・Python・Rails など言語別の対処法
  • 再起動後も解決しない TIME_WAIT 問題への対処


目次

結論:先に答えを出す

# ① 使用中のポートとプロセスを確認(3000番ポートの場合)
lsof -i :3000
ss -tlnp | grep :3000

# ② プロセスを終了(PIDを確認してから)
kill -9 <PID>

# ③ ポート番号で一発終了(確認なし・注意して使う)
lsof -ti :3000 | xargs kill -9

# ④ プロセス名で終了
pkill -f "node"
pkill -f "python"

エラーの意味

EADDRINUSE“Error: Address Already In Use” の略です。

指定したポート番号(例:3000)がすでに別のプロセスに使われているため、新しくサーバーを起動できないことを示しています。

Error: listen EADDRINUSE: address already in use :::3000
                                                    ^^^^
                                              このポートが使用中

:::3000 は IPv6 の全インターフェースの 3000 番ポートを意味します。0.0.0.0:3000 は IPv4 での表記です。


原因パターン

パターン1:同じアプリを二重起動した

最も多いケースです。

# 1回目の起動(正常)
node app.js

# 別ターミナルや間違えてもう1回起動 → エラー
node app.js
# Error: listen EADDRINUSE: address already in use :::3000

パターン2:前回のプロセスが残っている

Ctrl+C で止めたつもりが止まっていない、クラッシュして残ったままになっている場合です。

# 前回の node プロセスが残っている
ps aux | grep node
# user  12345  ... node app.js  ← これが残っている

パターン3:別のアプリが同じポートを使っている

よくある組み合わせ:

3000番:React・Next.js・Rails・Grafana
4200番:Angular
5000番:Flask・Python
8000番:Django・Python
8080番:Tomcat・各種 Web サーバー
8443番:HTTPS の代替ポート

パターン4:TIME_WAIT 状態のソケットが残っている

サーバーを停止した直後に再起動しようとすると、OSレベルでソケットが TIME_WAIT 状態のまま残っていてポートを占有している場合があります。


使用中のポートとプロセスを特定する

lsof でポートを確認(最もよく使う)

# 特定ポートを使っているプロセスを確認
lsof -i :3000

# 出力例
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
node    12345  user   23u  IPv6  12345      0t0  TCP *:3000 (LISTEN)

# 複数ポートを一度に確認
lsof -i :3000 -i :8080

# すべての LISTEN ポートを確認
lsof -i -P -n | grep LISTEN

出力の見方:

意味
COMMANDプロセス名
PIDプロセスID
USER実行ユーザー
NAMEアドレス:ポート (状態)

ss でポートを確認(モダンな方法)

# 特定ポートを確認
ss -tlnp | grep :3000

# 出力例
LISTEN  0  511  0.0.0.0:3000  0.0.0.0:*  users:(("node",pid=12345,fd=23))

# すべての LISTEN ポートを確認
ss -tlnp

# UDP も含めて確認
ss -tulnp

netstat でポートを確認(旧来の方法)

# netstat が使える環境
netstat -tlnp | grep :3000

# netstat がない場合
sudo apt install net-tools  # Ubuntu/Debian
sudo dnf install net-tools  # RHEL/CentOS

fuser でポートを確認

# ポートを使っているプロセスの PID を表示
fuser 3000/tcp

# プロセス名も表示
fuser -v 3000/tcp

プロセスを終了してポートを解放する

PID を確認してから終了(推奨)

# Step 1:PID を確認
lsof -i :3000
# node  12345  user ...

# Step 2:プロセスを終了
kill 12345        # 正常終了(SIGTERM)
kill -9 12345     # 強制終了(SIGKILL)

killkill -9 の違い:

コマンドシグナル動作
kill <PID>SIGTERM (15)正常終了を要求(プロセスが無視できる)
kill -9 <PID>SIGKILL (9)強制終了(無視できない)

通常は kill <PID> で十分です。応答しない場合は kill -9 を使います。

ポートから直接プロセスを終了

# lsof と xargs を組み合わせて一発終了
lsof -ti :3000 | xargs kill -9

# fuser で直接終了
fuser -k 3000/tcp

# ss で PID を取得して終了
ss -tlnp | grep :3000 | awk '{print $6}' | grep -oP 'pid=\K[0-9]+' | xargs kill

プロセス名で終了

# プロセス名で終了(同名プロセスすべて終了するので注意)
pkill node
pkill python
pkill ruby

# 強制終了
pkill -9 node

# 実行コマンド文字列でマッチ(-f オプション)
pkill -f "node app.js"
pkill -f "python manage.py"

# 終了前に対象プロセスを確認
pgrep -l node       # -l でプロセス名も表示
pgrep -a node       # -a でコマンド全体を表示

言語・フレームワーク別の対処法

Node.js / Express

# エラー例
Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (node:net:...)

# 使用中の node プロセスを確認
lsof -i :3000
ps aux | grep node

# 終了
lsof -ti :3000 | xargs kill -9
# または
pkill -f "node"

コード側での対処(自動ポート変更):

// app.js
const express = require('express');
const app = express();

const PORT = process.env.PORT || 3000;

const server = app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

// EADDRINUSE エラーをキャッチして別ポートで再試行
server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error(`Port ${PORT} is in use. Trying ${PORT + 1}...`);
    server.listen(PORT + 1);
  }
});

環境変数でポートを変更:

# 別のポートで起動
PORT=3001 node app.js

Next.js

# エラー例
Error: listen EADDRINUSE: address already in use :::3000

# 解決
lsof -ti :3000 | xargs kill -9

# 別ポートで起動
npx next dev -p 3001

# package.json に記述する場合
# "dev": "next dev -p 3001"

Python / Flask

# エラー例
OSError: [Errno 98] Address already in use

# 確認・終了
lsof -i :5000
lsof -ti :5000 | xargs kill -9

# 別ポートで起動
flask run --port 5001
python app.py  # app.py 内でポートを変更
# Flask のコードでポートを指定
if __name__ == '__main__':
    app.run(port=5001)  # ポートを変更

# または環境変数で
import os
port = int(os.environ.get('PORT', 5000))
app.run(port=port)

Python / Django

# エラー例
Error: [Errno 98] Address already in use

# 確認・終了
lsof -i :8000
lsof -ti :8000 | xargs kill -9

# 別ポートで起動
python manage.py runserver 8001
python manage.py runserver 0.0.0.0:8001

Ruby on Rails

# エラー例
Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE)

# Puma のピッドファイルが残っている場合
cat tmp/pids/server.pid  # PIDを確認
kill -9 $(cat tmp/pids/server.pid)
rm tmp/pids/server.pid

# または
lsof -ti :3000 | xargs kill -9

# 別ポートで起動
rails server -p 3001

Go

# エラー例
listen tcp :8080: bind: address already in use

# 確認・終了
lsof -i :8080
lsof -ti :8080 | xargs kill -9
// コード側でエラーハンドリング
package main

import (
    "log"
    "net/http"
)

func main() {
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatalf("Failed to start server: %v", err)
        // "address already in use" が含まれていれば別ポートを試みる
    }
}

PM2(Node.js プロセスマネージャ)

# PM2 で管理しているプロセスを確認
pm2 list
pm2 status

# 特定のアプリを再起動
pm2 restart app-name

# すべて停止
pm2 stop all
pm2 delete all

# PM2 管理外のプロセスが使っている場合
lsof -ti :3000 | xargs kill -9
pm2 start app.js

TIME_WAIT によるポート占有の解決

サーバーを再起動した直後に EADDRINUSE が出る場合、TIME_WAIT 状態のソケットが残っていることがあります。

# TIME_WAIT 状態を確認
ss -tnp | grep TIME-WAIT | grep :3000
netstat -tnp | grep TIME_WAIT | grep :3000

解決方法1:少し待つ

TIME_WAIT は通常 60〜120秒で自動的に解消されます。急がない場合はそのまま待つのが最も安全です。

解決方法2:SO_REUSEADDR オプションを使う

アプリのコードで SO_REUSEADDR を設定すると TIME_WAIT のポートを再利用できます。

Node.js(net モジュール):

const net = require('net');
const server = net.createServer();

// SO_REUSEADDR を設定
server.listen({
  host: '0.0.0.0',
  port: 3000,
  exclusive: false
});

Express や http.createServer では自動的に SO_REUSEADDR が設定されているため、通常は問題になりません。

Python:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 追加
sock.bind(('0.0.0.0', 5000))

解決方法3:sysctl で TIME_WAIT を短縮

# TIME_WAIT のタイムアウトを確認
cat /proc/sys/net/ipv4/tcp_fin_timeout
# デフォルト: 60(秒)

# 短縮する(開発環境向け・本番環境では慎重に)
sudo sysctl -w net.ipv4.tcp_fin_timeout=15

# TIME_WAIT ソケットの再利用を有効化
sudo sysctl -w net.ipv4.tcp_tw_reuse=1

# 恒久設定(/etc/sysctl.conf に追記)
echo "net.ipv4.tcp_fin_timeout = 15" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_tw_reuse = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

再発防止:開発環境での設定

起動スクリプトでポートを自動解放

#!/bin/bash
# start.sh:起動前に自動でポートを解放

PORT=${PORT:-3000}

# 使用中のプロセスがあれば終了
if lsof -ti :$PORT > /dev/null 2>&1; then
  echo "Port $PORT is in use. Killing process..."
  lsof -ti :$PORT | xargs kill -9
  sleep 1
fi

# サーバー起動
node app.js

package.json のスクリプトに組み込む

{
  "scripts": {
    "start": "node app.js",
    "dev": "node app.js",
    "kill": "lsof -ti :3000 | xargs kill -9 || true",
    "restart": "npm run kill && npm run dev"
  }
}
# 使い方
npm run kill    # ポートを解放
npm run restart # 解放してから起動

空きポートを自動で探す

// Node.js で空きポートを自動検出
const net = require('net');

function findAvailablePort(startPort) {
  return new Promise((resolve) => {
    const server = net.createServer();
    server.listen(startPort, () => {
      const { port } = server.address();
      server.close(() => resolve(port));
    });
    server.on('error', () => {
      resolve(findAvailablePort(startPort + 1));
    });
  });
}

// 使い方
findAvailablePort(3000).then((port) => {
  app.listen(port, () => {
    console.log(`Server started on port ${port}`);
  });
});
# Python で空きポートを自動検出
import socket

def find_available_port(start_port=5000):
    port = start_port
    while True:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            try:
                s.bind(('', port))
                return port
            except OSError:
                port += 1

port = find_available_port(5000)
app.run(port=port)

Docker でのポート競合

# Docker コンテナがポートを使用中の場合
docker ps | grep 3000

# コンテナを停止
docker stop コンテナID

# すべてのコンテナを停止
docker stop $(docker ps -q)

# docker-compose の場合
docker-compose down
docker-compose up

# ポートマッピングを変更して起動
docker run -p 3001:3000 イメージ名  # ホスト側を 3001 に変更
# docker-compose.yml でポートを変更
services:
  app:
    ports:
      - "3001:3000"  # ホスト:コンテナ

トラブルシューティング

lsof で何も表示されないのにエラーが出る

# IPv4 と IPv6 を別々に確認
lsof -i 4 -i :3000  # IPv4
lsof -i 6 -i :3000  # IPv6

# sudo が必要な場合
sudo lsof -i :3000

# ss でも確認
sudo ss -tlnp | grep :3000

kill しても解放されない

# プロセスが zombie 状態になっている可能性
ps aux | grep <PID>
# Z が表示される → zombie プロセス

# 親プロセスを確認して終了
pstree -p | grep <PID>
# 親プロセスの PID を終了すると zombie も消える
kill -9 <親PID>

# それでも解放されない場合は再起動
sudo reboot

sudo なしで 1024 番以下のポートを使いたい

# 1024番以下はデフォルトで root 権限が必要
# ← ポートが 80・443 などの場合

# 解決策1:環境変数でポートを変更
PORT=8080 node app.js

# 解決策2:authbind を使う
sudo apt install authbind
sudo touch /etc/authbind/byport/80
sudo chmod 777 /etc/authbind/byport/80
authbind node app.js

# 解決策3:setcap で Node.js に権限を付与
sudo setcap 'cap_net_bind_service=+ep' $(which node)
node app.js  # sudo なしで 80 番を使える

よくある質問(FAQ)

Q1. kill -9kill はどちらを使うべきですか?

まず kill <PID>(SIGTERM)を試してください。正常にシャットダウン処理が走り、ファイルのクローズや後処理が行われます。応答しない場合に kill -9 <PID>(SIGKILL)を使います。-9 は後処理なしで強制終了するため、データが壊れる可能性があります。

Q2. プロセスを終了したのにまだエラーが出ます

TIME_WAIT 状態のソケットが残っている可能性があります。ss -tnp | grep TIME-WAIT で確認し、数秒〜数分待つか、SO_REUSEADDR をコードに設定してください。

Q3. どのポートを使えばいいですか?

1〜1023     : Well-known ports(root権限必要)
1024〜49151 : Registered ports(一般ユーザーが使える)
49152〜65535: Dynamic/Private ports(一時的な使用向け)

開発でよく使われる安全なポート番号:
3000, 3001, 4000, 5000, 8000, 8080, 8888, 9000

Q4. Windows でも同じコマンドが使えますか?

Windowsでは以下のコマンドを使います。

# ポートを確認
netstat -ano | findstr :3000

# PID を確認して終了
taskkill /PID <PID> /F

# または PowerShell
Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess
Stop-Process -Id <PID> -Force

Q5. CI/CD 環境で発生する場合は?

# CI で前のジョブのプロセスが残っている場合
# 起動前にポートを確認・解放するステップを追加

# GitHub Actions の例
- name: Kill process on port 3000
  run: |
    lsof -ti :3000 | xargs kill -9 || true
    
- name: Start server
  run: node app.js &

まとめ

EADDRINUSE: address already in use指定したポートがすでに別のプロセスに使われていることを示すエラーです。

対処の手順:

# 1. 使用中のプロセスを確認
lsof -i :3000

# 2. PID を確認してプロセスを終了
kill -9 <PID>

# 3. または一発で終了
lsof -ti :3000 | xargs kill -9

それでも解決しない場合:

  • TIME_WAIT を待つ(60秒程度)
  • 別のポートを使う(PORT=3001 node app.js
  • SO_REUSEADDR をコードに設定する

再発防止:

  • 起動スクリプトでポートを自動解放
  • 空きポートを自動検出するコードを書く

参考リンク

公式ドキュメント

関連記事(本サイト)


本記事は2026年6月時点の情報をもとに、Ubuntu 24.04 LTS・Node.js 20.x・Python 3.12 での動作確認に基づき作成しています。環境によってコマンドの挙動が異なる場合があるため、最新情報は各公式ドキュメントをご確認ください。