Cách khắc phục lỗi 'dial tcp: connect: connection refused' trong Go

beginner🔷 Go2026-06-10| Các ứng dụng Go (Golang) chạy trên Linux, macOS hoặc Windows, thường liên quan đến PostgreSQL, MySQL, Redis hoặc microservices.

Error Message

dial tcp 127.0.0.1:5432: connect: connection refused
#golang#networking#docker#postgresql#troubleshooting

Giải mã lỗiBạn chạy lệnh go run main.go và thay vì ứng dụng hoạt động, bạn nhận được một loạt thông báo kết thúc bằng connection refused. Thật khó chịu, nhưng thông báo này thực chất khá cụ thể. Gói net của Go đưa ra lỗi này khi mã nguồn của bạn tìm thấy IP mục tiêu (như 127.0.0.1) thành công, nhưng hệ điều hành tại đích đến đó đã chủ động từ chối yêu cầu trên cổng bạn đã chọn (như 5432).

Hãy tưởng tượng việc này giống như gọi đến một số điện thoại đúng, nhưng người ở đầu dây bên kia dập máy ngay lập tức vì họ không nhận cuộc gọi trên đường dây cụ thể đó.

Tại sao kết nối thất bạiHầu hết các lập trình viên gặp phải lỗi này vì một trong bốn lý do sau:

  • Dịch vụ không hoạt động: Cơ sở dữ liệu của bạn (PostgreSQL, Redis, v.v.) thực tế chưa được chạy.- Sai cổng (port): Bạn đang cố kết nối với cổng 5432, nhưng dịch vụ thực tế đang lắng nghe trên cổng 5433 hoặc 8080.- Bị cô lập: Dịch vụ đang chạy nhưng chỉ lắng nghe các lưu lượng truy cập nội bộ (local), trong khi bạn đang cố gắng truy cập nó từ một giao diện mạng khác.- Bẫy Docker: Ứng dụng Go của bạn nằm trong một container và nó coi localhost là chính nó, thay vì là máy tính của bạn.## Các bước khắc phục cụ thể### 1. Kiểm tra trạng thái dịch vụĐầu tiên, hãy đảm bảo dịch vụ mục tiêu thực sự đang hoạt động. Nếu bạn đang sử dụng PostgreSQL trên cổng 5432, hãy kiểm tra trạng thái của nó ngay lập tức. Một dịch vụ bị sập hoặc chưa bao giờ khởi động là nguyên nhân phổ biến nhất.
# Trên Linux (systemd) systemctl status postgresql  # Trên macOS (Homebrew) brew services list

Nếu trạng thái là inactive hoặc stopped, hãy khởi động nó. Nếu nó chưa được cài đặt, đó chính là trở ngại đầu tiên của bạn.

2. Kiểm tra Cổng và Địa chỉChuỗi kết nối Go của bạn có thực sự khớp với thực tế không? Một nỗ lực kết nối TCP tiêu chuẩn trong Go sẽ trông như thế này:

// Thử thực hiện bắt tay TCP conn, err := net.Dial("tcp", "127.0.0.1:5432") if err != nil {     log.Fatalf("Kết nối thất bại: %v", err) }

Kiểm tra xem có dịch vụ nào thực sự đang lắng nghe trên cổng đó hay không bằng cách sử dụng lsof. Nếu kết quả trống, không có dịch vụ nào đang chiếm giữ cổng đó.

# Tìm các dịch vụ lắng nghe trên cổng 5432 sudo lsof -i :5432 # Hoặc sử dụng netstat để kiểm tra nhanh netstat -tuln | grep 5432

3. Giải mã bí ẩn 'Localhost' trong DockerĐây là sai lầm phổ biến nhất trong phát triển phần mềm hiện đại. Khi mã Go của bạn chạy bên trong một Docker container, 127.0.0.1 sẽ trỏ đến loopback nội bộ của container, chứ không phải máy chủ (host) của bạn. Cơ sở dữ liệu của bạn không nằm trong container đó, vì vậy kết nối sẽ thất bại ngay lập tức.

Cập nhật chuỗi kết nối dựa trên hệ điều hành của bạn:

  • macOS và Windows: Thay 127.0.0.1 bằng host.docker.internal.- Linux: Sử dụng IP của gateway (thường là 172.17.0.1) hoặc chạy container với --network="host" để chia sẻ ngăn xếp mạng của máy chủ.### 4. Kiểm tra địa chỉ ràng buộc (Bind Address)Đôi khi một dịch vụ bị giới hạn. Nó có thể được cấu hình để chỉ lắng nghe trên 127.0.0.1, điều đó có nghĩa là nó sẽ bỏ qua mọi yêu cầu đến từ IP bên ngoài hoặc Docker bridge. Hãy xem tệp cấu hình postgresql.conf hoặc tệp tương tự:
# postgresql.conf listen_addresses = 'localhost'  # Nghiêm ngặt: chỉ các ứng dụng cục bộ mới có thể kết nối listen_addresses = '*'          # Mở: cho phép kết nối từ bất kỳ giao diện mạng nào

Sau khi thay đổi thành '*', bạn phải khởi động lại dịch vụ để các thay đổi có hiệu lực.

Xác minh kết quả trong 5 giâyĐừng đợi ứng dụng Go biên dịch xong chỉ để kiểm tra bản sửa lỗi. Hãy sử dụng nc (netcat) để xem cổng có đang mở và chấp nhận lưu lượng hay không:

# Kiểm tra ping nhanh nc -vz 127.0.0.1 5432

Một kết nối thành công sẽ trả về: Connection to 127.0.0.1 port 5432 [tcp/postgresql] succeeded!. Nếu nó vẫn báo bị từ chối (refused), vấn đề nằm ở tường lửa hoặc cấu hình dịch vụ của bạn, không phải ở mã nguồn Go.

Mẹo chuyên nghiệp để ứng dụng ổn định- Tránh Hardcoding: Sử dụng các biến môi trường như DB_HOST=127.0.0.1. Điều này cho phép bạn chuyển sang URL production mà không cần biên dịch lại.- Triển khai cơ chế thử lại (Retries): Các cơ sở dữ liệu thường mất 5–10 giây để khởi tạo hoàn toàn. Hãy sử dụng một vòng lặp thử lại trong Go để thử kết nối 3–5 lần trước khi bỏ cuộc.- Wait-For-It: Nếu sử dụng Docker Compose, hãy sử dụng kiểm tra sức khỏe (health check) depends_on để đảm bảo cơ sở dữ liệu hoạt động ổn định trước khi binary Go bắt đầu chạy.

Related Error Notes