PyMySQL

raw JSON →
1.1.2 verified Tue May 12 auth: no python install: verified quickstart: verified

PyMySQL is a pure-Python MySQL client library, fully compliant with PEP 249 (Python Database API Specification v2.0). It enables Python applications to connect to MySQL and MariaDB databases without requiring binary extensions. The library is actively maintained, with version 1.1.2 released on August 24, 2025, and supports standard DB-API 2.0 features like cursors, transactions, and parameterized queries.

pip install PyMySQL
error ModuleNotFoundError: No module named 'pymysql'
cause The 'pymysql' library is not installed in the Python environment being used, or there is a typo in the import statement.
fix
Install the 'pymysql' package using pip: pip install pymysql.
error pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'hostname' ([Errno 111] Connection refused)")
cause The Python application cannot establish a connection with the MySQL server, often due to an incorrect host or port, the MySQL server not running, or firewall restrictions.
fix
Verify the MySQL server is running, check the host address and port (default is 3306), ensure no firewalls are blocking the connection, and confirm the correct host and port in the pymysql.connect() call. Using '127.0.0.1' instead of 'localhost' can sometimes resolve the issue.
error Authentication plugin 'caching_sha2_password' cannot be loaded
cause This error occurs when a PyMySQL client attempts to connect to a MySQL 8.0+ server (which defaults to 'caching_sha2_password' authentication) but the client's underlying MySQL client libraries do not support this plugin.
fix
Change the MySQL user's authentication method to mysql_native_password using an SQL command: ALTER USER 'your_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';.
error AttributeError: 'NoneType' object has no attribute 'cursor'
cause This indicates that the database connection object is 'None', meaning the attempt to connect to the database failed (e.g., due to incorrect credentials or server unavailability) and subsequently, `connection.cursor()` was called on a non-existent connection.
fix
Ensure the database connection is successfully established by wrapping the connection attempt in a try-except block to catch pymysql.err.OperationalError or similar connection exceptions, and validate connection parameters (host, user, password, db) before attempting to create a cursor.
error pymysql.err.OperationalError: (2006, "MySQL server has gone away (BrokenPipeError(32, 'Broken pipe'))") OR pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')
cause The MySQL server closed the connection unexpectedly, often due to client-side or server-side timeouts (e.g., `wait_timeout`, `net_write_timeout`), large queries exceeding `max_allowed_packet`, or the server being restarted.
fix
Increase MySQL server configuration parameters like wait_timeout, interactive_timeout, or net_write_timeout to allow longer idle connections. If dealing with large queries, increase max_allowed_packet. For very long operations, consider re-establishing the connection or sending keep-alive signals.
breaking PyMySQL 1.0.0 introduced several backward-incompatible changes, dropping support for Python 2.7 and 3.5. `connect()` arguments became keyword-only, and the `db` and `passwd` parameters were deprecated in favor of `database` and `password` respectively. Support for the `old_password` authentication method was also removed.
fix Ensure your project uses Python 3.6+ and update `pymysql.connect()` calls to use keyword arguments for all parameters, especially `database` and `password`. Review and update authentication methods if `old_password` was in use.
breaking As of PyMySQL 1.1.1, `Cursor.execute()` explicitly prohibits dictionary parameters to prevent potential SQL injection vulnerabilities. Passing a dictionary directly will raise an error.
fix Always use a sequence (tuple or list) of parameters with `cursor.execute()` for parameterized queries. For example, `cursor.execute('INSERT INTO users VALUES (%s, %s)', (value1, value2))` is correct, `cursor.execute('INSERT INTO users VALUES (%(key1)s, %(key2)s)', {'key1': value1, 'key2': value2})` is now forbidden.
deprecated The direct access to error classes via the `Cursor` object (e.g., `cursor.Error`) will be removed after June 2024. Also, `Connection.set_charset(charset)` and the usage of `db` and `passwd` parameters in `connect()` will emit `DeprecationWarning`s.
fix Refer to error classes directly from the `pymysql` module (e.g., `pymysql.Error`). Avoid `Connection.set_charset()` and use `charset` parameter in `pymysql.connect()` instead. Update `connect()` calls to use `database` and `password` parameters.
gotcha By default, PyMySQL connections are not in autocommit mode. Changes made via `INSERT`, `UPDATE`, or `DELETE` statements will not be saved to the database unless `connection.commit()` is explicitly called. Closing a connection without committing will result in a rollback of uncommitted changes.
fix Always call `connection.commit()` after performing data modification operations, or set `autocommit=True` when establishing the connection if that behavior is desired. Use `with connection:` for reliable connection handling which includes `commit()` on success or `rollback()` on exceptions.
gotcha PyMySQL does not provide built-in connection pooling. For applications requiring efficient connection management in multi-threaded or high-concurrency environments, external libraries such as `DBUtils.PooledDB` or `pymysql-pool` are necessary to avoid overhead from frequent connection establishment and teardown.
fix Integrate a connection pooling library (e.g., `pip install DBUtils` and use `PooledDB` or `pip install pymysql-pool`) into your application architecture.
gotcha The "MySQL server has gone away" error (`pymysql.err.OperationalError: (2006, 'MySQL server has gone away')`) is a common issue often caused by long idle connections timing out, large query packets exceeding server limits, or network interruptions. This can happen if the Python application holds a connection longer than the MySQL server's `wait_timeout` setting.
fix Implement connection `ping()` checks before executing queries (`connection.ping(reconnect=True)` can re-establish the connection if it dropped, though its default behavior has changed in related drivers). Consider increasing MySQL server's `wait_timeout` or `max_allowed_packet` if large queries are the cause. Use connection pooling to manage connection lifecycle effectively.
gotcha The 'Can't connect to MySQL server' error (e.g., `pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")`) indicates that PyMySQL was unable to establish a connection to the specified MySQL server. This is often due to the MySQL server not running, being inaccessible from the host where the application is running (e.g., incorrect host/port, firewall blocking connection), or incorrect network configuration.
fix Ensure the MySQL server is running and accessible from the application's host. Verify the host, port, username, and password provided to `pymysql.connect()` are correct. Check firewall rules on both the client and server machines. If connecting to `localhost`, ensure the server is configured to accept local connections on the correct port (default is 3306).
gotcha The 'Can't connect to MySQL server' error (code 2003, often with 'Connection refused' or 'Unknown MySQL server host') indicates a failure to establish an initial connection to the MySQL server. This is typically due to the server not running, incorrect host/port in connection parameters, network issues, or a firewall blocking the connection.
fix Verify that the MySQL server is running and accessible from the client's host. Ensure the `host` and `port` parameters in `pymysql.connect()` are correct. Check server-side configuration (e.g., `bind-address` in `my.cnf` or `my.ini`) and firewall rules to allow incoming connections on the MySQL port (default 3306).
pip install PyMySQL[rsa]
pip install PyMySQL[ed25519]
python os / libc variant status wheel install import disk
3.10 alpine (musl) PyMySQL - - 0.07s 18.1M
3.10 alpine (musl) ed25519 - - 0.07s 23.6M
3.10 alpine (musl) rsa - - 0.17s 33.6M
3.10 slim (glibc) PyMySQL - - 0.06s 19M
3.10 slim (glibc) ed25519 - - 0.03s 24M
3.10 slim (glibc) rsa - - 0.10s 34M
3.11 alpine (musl) PyMySQL - - 0.14s 20.0M
3.11 alpine (musl) ed25519 - - 0.14s 25.9M
3.11 alpine (musl) rsa - - 0.23s 35.7M
3.11 slim (glibc) PyMySQL - - 0.12s 21M
3.11 slim (glibc) ed25519 - - 0.07s 27M
3.11 slim (glibc) rsa - - 0.15s 36M
3.12 alpine (musl) PyMySQL - - 0.06s 11.9M
3.12 alpine (musl) ed25519 - - 0.06s 17.7M
3.12 alpine (musl) rsa - - 0.22s 27.5M
3.12 slim (glibc) PyMySQL - - 0.10s 12M
3.12 slim (glibc) ed25519 - - 0.07s 18M
3.12 slim (glibc) rsa - - 0.15s 28M
3.13 alpine (musl) PyMySQL - - 0.06s 11.5M
3.13 alpine (musl) ed25519 - - 0.06s 17.4M
3.13 alpine (musl) rsa - - 0.14s 27.2M
3.13 slim (glibc) PyMySQL - - 0.10s 12M
3.13 slim (glibc) ed25519 - - 0.06s 18M
3.13 slim (glibc) rsa - - 0.15s 28M
3.9 alpine (musl) PyMySQL - - 0.07s 17.6M
3.9 alpine (musl) ed25519 - - 0.04s 23.9M
3.9 alpine (musl) rsa - - 0.17s 33.9M
3.9 slim (glibc) PyMySQL - - 0.06s 18M
3.9 slim (glibc) ed25519 - - 0.08s 24M
3.9 slim (glibc) rsa - - 0.13s 34M

This quickstart demonstrates how to establish a connection to a MySQL database, insert a record, commit the transaction, and fetch data using `pymysql`. It uses `DictCursor` for results as dictionaries and includes error handling and proper connection closing. Remember that `PyMySQL` does not autocommit by default, so explicit `connection.commit()` is necessary.

import pymysql.cursors
import os

# Configure connection details (replace with your actual database info or environment variables)
host = os.environ.get('MYSQL_HOST', 'localhost')
user = os.environ.get('MYSQL_USER', 'root')
password = os.environ.get('MYSQL_PASSWORD', 'your_password')
database = os.environ.get('MYSQL_DATABASE', 'testdb')

try:
    # Connect to the database
    connection = pymysql.connect(host=host,
                                 user=user,
                                 password=password,
                                 database=database,
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)

    print(f"Successfully connected to MySQL database: {database}")

    with connection.cursor() as cursor:
        # Example: Create a new record
        sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
        cursor.execute(sql, ('webmaster@example.com', 'super_secret'))

        # connection is not autocommit by default. So you must commit to save your changes.
        connection.commit()
        print(f"Inserted {cursor.rowcount} row(s).")

        # Example: Read a single record
        sql = "SELECT `id`, `email`, `password` FROM `users` WHERE `email`=%s"
        cursor.execute(sql, ('webmaster@example.com',))
        result = cursor.fetchone()
        print(f"Fetched record: {result}")

except pymysql.Error as e:
    print(f"Error connecting or querying MySQL: {e}")
finally:
    if 'connection' in locals() and connection.open:
        connection.close()
        print("Database connection closed.")