Mô Tả Lỗi
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (node:net:1739:16)
at listenInCluster (node:net:1787:12)
at Server.listen (node:net:1875:7)
at Function.listen (/app/node_modules/express/lib/application.js:635:24)
Port 3000 đang bị chiếm. Node.js cố gắng lắng nghe trên port đó, phát hiện có thứ gì đó đang chạy và dừng lại. Hai process không thể dùng chung một TCP port — vì vậy một trong số chúng phải bị dừng.
Nguyên Nhân
Ba nguyên nhân phổ biến:
- Một server instance trước đó bị crash hoặc bạn đóng cửa sổ terminal đột ngột. Process Node.js vẫn tiếp tục chạy ngầm, giữ nguyên port 3000.
- Thứ gì đó đã chiếm port đó rồi — một ứng dụng Node.js khác, Webpack dev server, ứng dụng Python Flask, v.v.
- Bạn khởi động lại quá nhanh. Hệ điều hành cần một khoảng thời gian (thường vài giây) để thu hồi port sau khi process cũ thoát. Nhấn Ctrl+C rồi chạy
npm startngay lập tức? Bạn có thể đã không kịp chờ.
Cách Sửa Từng Bước
Bước 1: Tìm process đang chiếm port
Trên macOS / Linux:
lsof -i :3000
Ví dụ kết quả:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 1234 alice 23u IPv6 12345 0t0 TCP *:3000 (LISTEN)
Cột PID — 1234 trong ví dụ này — là thứ bạn cần ở bước tiếp theo.
Muốn dùng ss hoặc netstat? Cũng được:
# Dùng ss
ss -tlnp | grep :3000
# Dùng netstat
netstat -tlnp | grep :3000
Trên Windows (Command Prompt hoặc PowerShell):
netstat -ano | findstr :3000
Ví dụ kết quả:
TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 5678
Số cuối cùng (5678) chính là PID.
Bước 2: Kill process
Trên macOS / Linux:
kill -9 1234
Thay 1234 bằng PID thực tế bạn tìm được. Hoặc bỏ qua bước tìm kiếm và làm gọn trong một lệnh:
kill -9 $(lsof -ti :3000)
Trên Windows (chạy với quyền Administrator):
taskkill /PID 5678 /F
Bước 3: Khởi động lại server Node.js
node app.js
# hoặc
npm start
# hoặc
npx ts-node src/index.ts
Cách Khắc Phục Khác: Dùng Port Khác
Có thể process đang dùng port 3000 là cố ý — một ứng dụng khác bạn cần chạy. Không sao. Chỉ cần chuyển server sang port khác.
Trong code ứng dụng của bạn:
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Server đang chạy trên port ${PORT}`);
});
Hoặc đặt port khi khởi động mà không cần sửa code:
PORT=3001 node app.js
Trên Windows:
set PORT=3001 && node app.js
Sửa Lỗi Với nodemon / Chế Độ Watch Khi Phát Triển
Gặp lỗi này sau mỗi lần lưu file? nodemon có thể đang khởi động lại process trước khi hệ điều hành kịp thu hồi port. Thêm độ trễ 1 giây thường giải quyết được:
# nodemon.json
{
"delay": 1000
}
Nếu vẫn bị kẹt, hãy kill toàn bộ process Node và khởi động lại từ đầu:
# macOS / Linux — kill tất cả process Node
pkill -f node
# sau đó khởi động lại
npm run dev
Kiểm Tra Sau Khi Sửa
Chạy lại lệnh tìm kiếm sau khi đã kill process:
# macOS / Linux
lsof -i :3000
# Windows
netstat -ano | findstr :3000
Không có kết quả nghĩa là port đã trống. Khởi động server — nó sẽ chạy bình thường.
Muốn xác nhận server đang phản hồi không? Thử curl nhanh:
curl http://localhost:3000
# hoặc mở http://localhost:3000 trên trình duyệt
Mẹo Tránh Lỗi Này
- Ctrl+C tốt hơn đóng terminal — đóng cửa sổ terminal thường để lại process Node.js mồ côi. Nó vẫn chạy, vẫn giữ port. Ctrl+C gửi tín hiệu SIGINT và tắt đúng cách.
- Đọc port từ biến môi trường — hardcode
3000ổn cho đến khi nó không ổn nữa.process.env.PORT || 3000cho phép bạn đổi port bằng một biến môi trường duy nhất, không cần sửa code. - Thêm graceful shutdown handler trong môi trường production — giúp server giải phóng port đúng cách khi thoát:
process.on('SIGTERM', () => {
server.close(() => {
console.log('Server đã đóng');
process.exit(0);
});
});
- Dùng PM2? Chú ý instance cũ —
pm2 restart apptự xử lý việc chuyển tiếp. Để khởi động sạch, hãy chạypm2 stop alltrước để đảm bảo không còn gì đang chiếm port của bạn.

