How to fix CR_ALREADY_CONNECTED (2058): Handle already connected in MySQL

MySQLINTERMEDIATEMEDIUMUpdated Dec 29, 2025· 160 views

This MySQL client error occurs when attempting to call mysql_real_connect() on a connection handle that is already connected to a MySQL server. The error indicates that your code is reusing a connection handle without properly closing the previous connection first, or attempting to reconnect on an already-active connection.

Quick fix

Fixes 2058

// WRONG - attempting to connect twice without closing
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
// ... do work ...
mysql_real_connect(conn, host2, user2, password2, db2, 0, NULL, 0);  // ERROR 2058!

// CORRECT - close before reconnecting
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
// ... do work ...
mysql_close(conn);  // Close first

conn = mysql_init(NULL);  // Allocate new handle
mysql_real_connect(conn, host2, user2, password2, db2, 0, NULL, 0);  // Now safe
  1. Always close connections before reconnecting
  2. Use separate handles for concurrent connections
  3. Implement proper connection pooling
  4. Check connection state before operations
mysql — error
// WRONG - attempting to connect twice without closing
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
// ... do work ...
mysql_real_connect(conn, host2, user2, password2, db2, 0, NULL, 0); // ERROR 2058!
// CORRECT - close before reconnecting
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
// ... do work ...
mysql_close(conn); // Close first
conn = mysql_init(NULL); // Allocate new handle
mysql_real_connect(conn, host2, user2, password2, db2, 0, NULL, 0); // Now safe
CR_ALREADY_CONNECTED (2058): Handle already connected

What this error means

The CR_ALREADY_CONNECTED (2058) error is a MySQL client error that occurs when the MySQL client library detects an attempt to establish a connection using a handle that already has an active connection session. This is a protocol violation - the MySQL client library is designed with the rule that each connection handle (MYSQL* pointer or equivalent in different languages) represents a single database session. Key aspects of this error: 1. **Connection Handle State**: A connection handle maintains state about the active database session. When already connected, attempting to call a connection function again violates the expected state machine. 2. **Per-Handle Connection Rule**: MySQL's C client library follows a strict one-handle-per-connection model. You cannot reuse the same handle to connect to multiple servers or reconnect without closing the previous session. 3. **Thread Safety**: This error is particularly common in multi-threaded applications where connection handles are shared across threads or when a handle is returned from a connection pool while still in a connected state. 4. **Connection Pool Issues**: Modern connection pooling libraries manage handles internally. If pool logic incorrectly returns a live handle to another consumer, that consumer may attempt to "reconnect" and trigger this error. This error primarily affects C/C++ code using the MySQL C API, but can manifest in other languages that wrap the C API (such as older PHP mysql extensions, Node.js bindings, or custom connectors).

Typical symptoms

  • Application throws "CR_ALREADY_CONNECTED" or "Handle already connected" error
  • Database connection attempt immediately fails without network delays
  • Error occurs inconsistently or only under concurrent load
  • Connection pool returns connections that cause errors when reused
  • Multi-threaded application crashes with this error periodically
  • Error happens when application tries to reconnect after a temporary disconnection
  • Connection pooling works initially but fails after a certain number of requests
  • Specific threads or workers consistently fail to establish connections

Common causes

  1. Calling mysql_real_connect() twice on the same MYSQL* handle without calling mysql_close() between them
  2. Connection pooling logic returns a handle that is still in connected state
  3. Attempting to reconnect on the same connection object without closing the previous session
  4. Race condition in multi-threaded code where multiple threads use the same connection handle
  5. Incorrectly sharing a MYSQL* pointer across multiple threads without synchronization
  6. Connection pool not properly tracking handle state when returning connections
  7. Reusing a connection handle from a pool without verifying its disconnected state
  8. Legacy code with incorrect connection lifecycle management

How to fix "CR_ALREADY_CONNECTED (2058): Handle already connected"

1Always close connections before reconnecting

The fundamental rule is that each connection handle must be closed before being reused:

c
// WRONG - attempting to connect twice without closing
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
// ... do work ...
mysql_real_connect(conn, host2, user2, password2, db2, 0, NULL, 0);  // ERROR 2058!

// CORRECT - close before reconnecting
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
// ... do work ...
mysql_close(conn);  // Close first

conn = mysql_init(NULL);  // Allocate new handle
mysql_real_connect(conn, host2, user2, password2, db2, 0, NULL, 0);  // Now safe

Always follow this pattern: Initialize → Connect → Use → Close → (repeat from Initialize if needed).

2Use separate handles for concurrent connections

For multi-threaded or concurrent applications, allocate one handle per connection:

c
// WRONG - sharing one handle across threads
MYSQL *shared_conn = mysql_init(NULL);
mysql_real_connect(shared_conn, host, user, password, db, 0, NULL, 0);

// Thread 1
mysql_query(shared_conn, "SELECT ...");  // May race with thread 2

// Thread 2 (concurrent)
mysql_query(shared_conn, "SELECT ...");  // DATA RACE!

// CORRECT - one handle per thread/connection
void* thread_func(void* arg) {
    MYSQL *conn = mysql_init(NULL);
    mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
    
    // Safe - this thread owns this connection
    mysql_query(conn, "SELECT ...");
    
    mysql_close(conn);
    return NULL;
}

Each concurrent connection needs its own MYSQL* handle. Use connection pooling libraries that enforce this rule.

3Implement proper connection pooling

For applications needing multiple connections, use a proper connection pool implementation:

python
# Python example with proper pooling
from mysql.connector import pooling

dbconfig = {
    "host": "localhost",
    "user": "myuser",
    "password": "mypassword",
    "database": "mydb"
}

# Create pool (not connecting yet)
pool = pooling.MySQLConnectionPool(
    pool_name="mypool",
    pool_size=5,  # Number of connections
    **dbconfig
)

# Each call gets a fresh connection
conn1 = pool.get_connection()  # Gets connection 1
conn2 = pool.get_connection()  # Gets connection 2 (different handle)

# Use connections
conn1.cursor().execute("SELECT ...")
conn2.cursor().execute("SELECT ...")

# Return to pool (ready for reuse)
conn1.close()
conn2.close()
javascript
// Node.js example with mysql2/promise pooling
const mysql = require('mysql2/promise');

const pool = mysql.createPool({
    connectionLimit: 10,
    host: 'localhost',
    user: 'myuser',
    password: 'mypassword',
    database: 'mydb'
});

// Each getConnection() returns a separate connection
const conn1 = await pool.getConnection();
const conn2 = await pool.getConnection();

await conn1.query("SELECT ...");
await conn2.query("SELECT ...");

conn1.release();  // Return to pool
conn2.release();  // Return to pool

Connection pools automatically manage handle lifecycle and prevent reuse of active connections.

4Check connection state before operations

Use mysql_ping() to verify connection state without reconnecting:

c
// Check if connection is still alive
if (mysql_ping(conn) != 0) {
    // Connection is dead, close and reconnect
    mysql_close(conn);
    conn = mysql_init(NULL);
    mysql_real_connect(conn, host, user, password, db, 0, NULL, 0);
} else {
    // Connection is alive, safe to use
    mysql_query(conn, "SELECT ...");
}
python
# Python - check connection status
try:
    cursor = conn.cursor()
    cursor.execute("SELECT 1")  # Lightweight query to verify
except mysql.connector.Error:
    # Connection dead, close and reconnect
    conn.close()
    conn = mysql.connector.connect(**config)

This avoids attempting to reconnect on an already-active handle.

5Fix connection pool implementation

If using a custom connection pool, ensure proper state management:

python
# WRONG - pool doesn't track connection state
class BrokenPool:
    def __init__(self):
        self.conn = mysql.connector.connect(**config)  # Single shared connection
    
    def get_connection(self):
        return self.conn  # Returns same handle every time!

# CORRECT - pool manages handles properly
class ProperPool:
    def __init__(self, size=5):
        self.available = []
        self.in_use = set()
        
        # Create pool of connections
        for _ in range(size):
            conn = mysql.connector.connect(**config)
            self.available.append(conn)
    
    def get_connection(self):
        if not self.available:
            raise Exception("No available connections")
        
        conn = self.available.pop()
        self.in_use.add(id(conn))
        return conn
    
    def return_connection(self, conn):
        # Verify connection state
        if conn.is_connected():
            self.in_use.discard(id(conn))
            self.available.append(conn)
        else:
            # Dead connection, create new one
            self.in_use.discard(id(conn))
            conn.close()
            self.available.append(
                mysql.connector.connect(**config)
            )
    
    def close_all(self):
        for conn in self.available:
            conn.close()
        for conn_id in self.in_use:
            # Try to close in-use connections
            pass

Proper pools track which connections are in use and never return an active connection.

6Review and fix reconnection logic

Audit code that handles reconnection on failure:

python
# WRONG - attempts to reconnect on same handle
def execute_with_retry(query, retries=3):
    for attempt in range(retries):
        try:
            cursor = conn.cursor()
            cursor.execute(query)
            return cursor.fetchall()
        except mysql.connector.Error as e:
            if attempt < retries - 1:
                conn.reconnect()  # ERROR 2058 if already connected!

# CORRECT - closes before reconnecting
def execute_with_retry(query, retries=3):
    global conn
    for attempt in range(retries):
        try:
            cursor = conn.cursor()
            cursor.execute(query)
            return cursor.fetchall()
        except mysql.connector.Error as e:
            if attempt < retries - 1:
                conn.close()  # Close first!
                conn = mysql.connector.connect(**config)  # Fresh connection
            else:
                raise

Always close before attempting to create a new connection on the same variable.

Advanced notes

CR_ALREADY_CONNECTED (2058) has several advanced considerations:

1. C API vs Higher-Level Libraries: This error is most common in C/C++ code using mysql_real_connect(). Higher-level libraries (mysql2/promise, mysqlx, SQLAlchemy) typically abstract away this complexity, but custom wrappers or legacy code may expose it.

2. Error Code Confusion: MySQL documentation has historically mentioned error 2059 for some cases. MariaDB Connector/C version 2.x had issues with error code mapping that were fixed in version 3.x. Check your MySQL client library version if error codes seem inconsistent.

3. Persistent Connections in PHP: The legacy PHP mysql extension (deprecated since PHP 5.5, removed in PHP 7.0) used persistent connections. Old code using mysql_connect() with persistent=true could trigger this if connection reuse was mishandled. Use mysqli or PDO with prepared statements.

4. Connection Pool Deadlocks: Improper pooling can cause deadlocks where all connections are checked out but held by stuck threads. Implement timeout mechanisms and connection validation:

python
try:
       conn = pool.get_connection(timeout=5)  # Wait max 5 seconds
   except TimeoutError:
       # Handle pool exhaustion

5. MySQL Cluster and Group Replication: In clustered MySQL environments, connection failures may trigger automatic reconnection attempts. Ensure cluster-aware connection managers don't violate the handle-per-connection rule.

6. Docker and Connection State: When containers restart or network fails, hanging connections may still have state. Implement aggressive timeout handling:

python
conn.set_charset_collation('utf8mb4', 'utf8mb4_unicode_ci')
   conn._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

7. Async/Await Patterns: In async JavaScript code, ensure each async operation gets its own connection from the pool, not a shared handle:

javascript
// WRONG
   let sharedConn;
   async function query1() { await sharedConn.query(...) }
   async function query2() { await sharedConn.query(...) }  // May race
   
   // CORRECT
   async function query1() {
       const conn = await pool.getConnection();
       try { return await conn.query(...) }
       finally { conn.release() }
   }

8. Testing: Test concurrent access patterns explicitly:

python
import threading
   threads = []
   for i in range(10):
       t = threading.Thread(target=concurrent_query, args=(i,))
       threads.append(t)
       t.start()
   for t in threads:
       t.join()

For production debugging, monitor connection pool metrics (available/in-use/total) and track connection lifecycle events.

Frequently asked questions

What does "2058" mean?
The CR_ALREADY_CONNECTED (2058) error is a MySQL client error that occurs when the MySQL client library detects an attempt to establish a connection using a handle that already has an active connection session. This is a protocol violation - the MySQL client library is designed with the rule that each connection handle (MYSQL* pointer or equivalent in different languages) represents a single database session. Key aspects of this error: 1.
How do I fix "2058"?
This MySQL client error occurs when attempting to call mysql_real_connect() on a connection handle that is already connected to a MySQL server. The error indicates that your code is reusing a connection handle without properly closing the previous connection first, or attempting to reconnect on an already-active connection.
What causes "2058"?
Calling mysql_real_connect() twice on the same MYSQL* handle without calling mysql_close() between them Connection pooling logic returns a handle that is still in connected state Attempting to reconnect on the same connection object without closing the previous session
Is the "2058" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading