How can I connect to MySQL in Python 3 on Windows?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Working with databases is one of the most common tasks in application development, and MySQL remains one of the most widely deployed relational databases in the world. If you are building a Python 3 application on Windows that needs to store or retrieve structured data, you will need a reliable way to connect to MySQL. This article walks you through two popular driver libraries, shows you how to perform basic CRUD operations, and introduces connection pooling for production workloads.
Installing the Driver Libraries
Python does not ship with a MySQL driver, so you need to install one. The two most popular choices are mysql-connector-python (Oracle's official pure-Python driver) and PyMySQL (a community-maintained pure-Python driver). Both install cleanly on Windows without a C compiler.
Choose one for your project. mysql-connector-python offers tighter integration with MySQL-specific features, while PyMySQL is lightweight and often used as a drop-in replacement in frameworks like Django and SQLAlchemy.
Connecting with mysql-connector-python
Once the package is installed, you create a connection by supplying the host, user, password, and database name. The pattern is the same whether you are on Windows, macOS, or Linux.
The cursor object is your handle for executing SQL statements and fetching results. Always close both the cursor and the connection when you are finished to free server resources.
Connecting with PyMySQL
PyMySQL follows the same DB-API 2.0 interface, so the code looks nearly identical.
Using DictCursor returns each row as a dictionary keyed by column name, which makes your code easier to read compared to positional tuples.
Performing CRUD Operations
Below is a complete example that creates a table, inserts a row, reads it back, updates it, and finally deletes it. The example uses mysql-connector-python, but the SQL and cursor API are the same with PyMySQL.
Notice that every write operation is followed by connection.commit(). MySQL connections created by these drivers default to autocommit off, so forgetting to commit is a frequent source of "missing data" bugs.
Connection Pooling
Opening a new database connection for every request is expensive. Connection pooling keeps a set of connections alive and hands them out on demand. mysql-connector-python includes a built-in pool.
For PyMySQL, you can achieve the same effect with the DBUtils or SQLAlchemy connection pool wrappers.
Common Pitfalls
- Forgetting to commit: Both drivers default to autocommit off. If you execute INSERT, UPDATE, or DELETE statements and do not call
connection.commit(), the changes are silently rolled back when the connection closes. - Hardcoding credentials: Putting passwords directly in source code is a security risk. Use environment variables or a
.envfile loaded withpython-dotenvinstead. - Not using parameterized queries: Building SQL with string concatenation (for example,
f"SELECT * FROM users WHERE id = {user_id}") opens the door to SQL injection. Always use%splaceholders and pass values as a tuple. - Ignoring connection timeouts: Long-lived connections can be dropped by the MySQL server (default
wait_timeoutis 8 hours). In production, use a connection pool or add reconnect logic to handle stale connections. - Skipping error handling: Database operations can fail for many reasons (network issues, constraint violations, deadlocks). Wrap your calls in try/except blocks and handle
mysql.connector.Errororpymysql.err.OperationalErrorexplicitly.
Summary
- Install either
mysql-connector-pythonorPyMySQLvia pip; both are pure Python and work on Windows without a C compiler. - Create a connection with host, user, password, and database parameters, then use a cursor to execute SQL.
- Always use parameterized queries (
%splaceholders) to prevent SQL injection. - Call
connection.commit()after every write operation because autocommit is off by default. - Use connection pooling in production to avoid the overhead of opening a new connection for every request.
Related reading
- How can I control user access to Amazon DynamoDB data via IAM?
- How can I create a KSQL table from a topic using a composite key?
- How can I create an external dictionary from url in clickhouse?
- How can I directly view blobs in MySQL Workbench
- How can I constrain a value parsed with argparse for example, restrict an integer to positive values?
- How can I convert a character to a integer in Python, and viceversa?
- How can I discover a mongo database's structure
- How can I do a FULL OUTER JOIN in MySQL?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.