Why This Happens
When you call db.Query, Go borrows a connection from the pool and ties it to the Rows object. The connection is returned to the pool only when Rows.Close() is called. If you forget to close Rows, the connection leaks and eventually the pool is exhausted, blocking all queries.
The Problem
func getUsers(db *sql.DB) ([]string, error) {
rows, err := db.Query("SELECT name FROM users")
if err != nil {
return nil, err
}
// rows never closed!
var names []string
for rows.Next() {
var name string
rows.Scan(&name)
names = append(names, name)
}
return names, nil
}The Fix
func getUsers(db *sql.DB) ([]string, error) {
rows, err := db.Query("SELECT name FROM users")
if err != nil {
return nil, err
}
defer rows.Close()
var names []string
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, err
}
names = append(names, name)
}
return names, rows.Err()
}Step-by-Step Fix
- 1
Identify unclosed rows
Find db.Query calls where rows.Close() is not called or not deferred.
- 2
Add defer rows.Close()
Add defer rows.Close() immediately after the error check on db.Query.
- 3
Check rows.Err()
Always check rows.Err() after the iteration loop to catch errors that occurred during iteration.
Bugsly catches this automatically
Bugsly's AI analyzes this error pattern in real-time, explains what went wrong in plain English, and suggests the exact fix — before your users even report it.
Try Bugsly free