Introduction

Go HTTP client connection pool runs out of available connections when response bodies are not properly closed or pool configuration is insufficient. This guide provides step-by-step diagnosis and resolution with specific commands and code examples.

Symptoms

Typical symptoms and error messages when this issue occurs:

bash
Get "https://api.example.com": dial tcp 10.0.0.1:443: connect: connection refused
http: no connections available in pool

Observable indicators: - Application logs show connection or operation failures - Error messages appear in system or application logs - Related dependent services may exhibit cascading failures

Common Causes

  1. 1.The connection pool exhaustion typically occurs when:
  2. 2.Response bodies are not closed after reading
  3. 3.MaxIdleConnsPerHost is set too low
  4. 4.Connection timeout is not configured

Step-by-Step Fix

Step 1: Check Current State

bash
lsof -p $(pgrep app) | grep TCP | wc -l

Step 2: Identify Root Cause

bash
netstat -an | grep ESTABLISHED | wc -l

Step 3: Apply Primary Fix

```go // Always close response body resp, err := client.Get(url) if err != nil { return err } defer resp.Body.Close() // Critical: must close

// Read entire body to allow connection reuse body, _ := io.ReadAll(resp.Body) ```

Apply this configuration and restart the application:

bash
go build && ./application

Step 4: Apply Alternative Fix (If Needed)

go
// Configure proper pool settings
transport := &http.Transport{
    MaxIdleConns:        100,
    MaxIdleConnsPerHost: 10,
    IdleConnTimeout:     90 * time.Second,
}
client := &http.Client{
    Transport: transport,
    Timeout:   30 * time.Second,
}

After applying this configuration, verify the connection pool behavior under load testing.

Step 5: Verify the Fix

After applying the fix, verify with:

bash
curl -v https://api.example.com/health && echo "Success"

Expected output should show successful operation without errors.

Common Pitfalls

  • Forgetting to close response bodies
  • Setting MaxIdleConnsPerHost too low
  • Not handling connection errors gracefully

Best Practices

  • Always use defer resp.Body.Close()
  • Configure reasonable timeouts (30s default)
  • Monitor connection pool metrics
  • Go Context Deadline Exceeded
  • Go TLS Certificate Verification Failed
  • Go DNS Resolution Failed