「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)
kill と kill -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 -9 と kill はどちらを使うべきですか?
まず 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をコードに設定する
再発防止:
- 起動スクリプトでポートを自動解放
- 空きポートを自動検出するコードを書く
参考リンク
公式ドキュメント
関連記事(本サイト)
- Linux「Too many open files」エラーの解決方法 – よくあるLinuxエラー
- Linux「command not found」エラーの解決方法 – よくあるLinuxエラー
- vmstat の見方・使い方 – サーバー監視
- Linux grep オプション一覧 – grepコマンドリファレンス
本記事は2026年6月時点の情報をもとに、Ubuntu 24.04 LTS・Node.js 20.x・Python 3.12 での動作確認に基づき作成しています。環境によってコマンドの挙動が異なる場合があるため、最新情報は各公式ドキュメントをご確認ください。
-
前の記事
Rails Solid Cache の使い方|セットアップから本番運用・Redis/Memcachedからの移行 2026.06.23
-
次の記事
【完全版】git merge で CONFLICT が発生したときの解決手順まとめc 2026.06.23
コメントを書く