Fix lỗi 'Only one usage of each socket address' — Windows Port Đã Bị Dùng

beginner🪟 Windows2026-03-18| Windows 10/11 — Node.js, Python, Java, .NET, hoặc bất kỳ ứng dụng TCP server nào

Error Message

Only one usage of each socket address (protocol/network address/port) is normally permitted
#windows#port#netstat#tcp

Bạn khởi động server và Windows báo lỗi:

Only one usage of each socket address (protocol/network address/port) is normally permitted

Đây là lỗi tương đương với EADDRINUSE trên Linux nhưng dành cho Windows. Một TCP port chỉ có thể được bind bởi một process tại một thời điểm — và có thứ gì đó đang chiếm port của bạn. Ứng dụng sẽ không khởi động được cho đến khi port đó được giải phóng.

Nguyên nhân

Có ba nguyên nhân chính. Thường gặp nhất là một trong số:

  • Một instance trước của ứng dụng bị crash hoặc không tắt sạch, khiến port bị khóa lại
  • Một service hệ thống (IIS, SQL Server, Apache, Hyper-V virtual switch) đã chiếm port ngay khi Windows khởi động
  • Windows tự động dành riêng dải port — điều này xảy ra sau khi bật Hyper-V, WSL2, hoặc Docker Desktop

Bước 1: Tìm process đang chiếm port

Mở Command Prompt với quyền Administrator và chạy:

netstat -ano | findstr :3000

Thay 3000 bằng số port thực tế của bạn. Kết quả trông như sau:

  TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       12345

Cột cuối cùng là PID (Process ID). Để xem chương trình nào đứng sau PID đó:

tasklist /FI "PID eq 12345"

Kết quả mẫu:

Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
node.exe                     12345 Console                    1     52,340 K

Bây giờ bạn đã biết chính xác process nào đang chiếm port.

Bước 2: Kill process đó

taskkill /PID 12345 /F

Flag /F buộc kết thúc process ngay lập tức. Nếu gặp thông báo Access is denied? Bạn cần mở terminal với quyền nâng cao — nhấp chuột phải vào Start menu và chọn Windows Terminal (Admin) hoặc Command Prompt (Admin).

PowerShell one-liner

Thích dùng PowerShell? Lệnh này tìm và kill process chỉ trong một dòng:

Stop-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess -Force

Muốn xem trước process sắp bị kill trước khi thực hiện:

Get-NetTCPConnection -LocalPort 3000 | Select-Object LocalPort, OwningProcess,
  @{n='ProcessName'; e={(Get-Process -Id $_.OwningProcess).Name}}

Kết quả mẫu:

LocalPort OwningProcess ProcessName
--------- ------------- -----------
     3000         12345 node

Trường hợp đặc biệt: Dải port bị Windows dành riêng

Sau khi bật Hyper-V, WSL2, hoặc Docker Desktop, Windows sẽ dành riêng các khối dynamic port khi khởi động. Khi port của bạn nằm trong khối bị dành riêng, việc kill process sẽ không có tác dụng — OS đang chặn ở tầng network stack.

Kiểm tra các port mà Windows đã dành riêng:

netsh interface ipv4 show excludedportrange protocol=tcp

Thấy port của bạn trong kết quả? Hãy chuyển sang port nằm ngoài dải bị dành riêng. Hoặc reset lại toàn bộ dải dynamic port:

netsh int ipv4 set dynamicport tcp start=49152 num=16384

Khởi động lại Windows sau khi thay đổi. Cần lưu ý: Hyper-V và Docker không chỉ chiếm dải 49152–65535 — chúng có thể dành riêng các khối trong dải 5000–9000 nữa. Luôn kiểm tra trực tiếp từ kết quả netsh trên máy của bạn thay vì tự cho rằng một port đang trống.

Bước 3: Xác nhận đã fix xong

Sau khi kill process, xác nhận port đã được giải phóng:

netstat -ano | findstr :3000

Không có kết quả nào nghĩa là port đã sẵn sàng. Khởi động server — lần này sẽ bind được mà không gặp lỗi.

Vẫn thấy dòng TIME_WAIT thay vì không có gì?

  TCP    0.0.0.0:3000           0.0.0.0:0              TIME_WAIT       0

Đó là kết nối vừa đóng đang trong quá trình dọn dẹp. Chờ 30–60 giây rồi thử lại, hoặc tạm thời chuyển sang port khác.

Phòng tránh

Nếu lỗi này xảy ra liên tục do ứng dụng crash giữa chừng mà không giải phóng port:

  • Node.js: Xử lý SIGTERM/SIGINT rõ ràng để đóng HTTP server trước khi thoát. Chạy dưới pm2 cũng giúp ích — nó tự động quản lý việc khởi động lại và dọn dẹp.
  • Python: Đặt SO_REUSEADDR trên socket trước khi gọi bind(). Dev server của Flask đã làm điều này mặc định; Gunicorn cũng xử lý đúng cách trong môi trường production.
  • Java / .NET: Thêm shutdown hook gọi server.close() — hoặc lệnh tương đương của framework — để port được giải phóng khi thoát, kể cả khi crash.

Trước khi hardcode bất kỳ port nào trong config, hãy kiểm tra xem port nào đang được dùng:

netstat -ano | findstr LISTENING

Máy dev thường có SQL Server (1433), IIS (80/443), và PostgreSQL (5432) âm thầm chạy nền. Chọn nhầm port đã bị chiếm chỉ làm trì hoãn vấn đề đến lúc runtime.

Related Error Notes