MySQL MCP Server
A high-quality Model Context Protocol (MCP) server implementation for MySQL databases. This server enables AI assistants like Claude to interact with MySQL databases through a standardized protocol.
Version: 0.2.0 | Protocol: MCP 2025-03-26 | Rust: 1.70+ | Status: Production Ready
Table of Contents
Features
- Schema Inspection: Retrieve table schemas and structure information
- Query Execution: Execute SQL queries (read-only by default for safety)
- Data Manipulation: Insert, update, and delete operations
- Database Context: Specify which database to use per query
- Safety Controls: Configurable query restrictions to prevent dangerous operations
- Connection Management: Robust connection handling with retry logic and pooling
- Error Handling: Comprehensive error reporting with detailed messages
- JSON-RPC 2.0 Protocol: Standardized communication via stdio
Installation
Prerequisites
- Rust 1.70+
- MySQL 5.7+ or MariaDB 10.2+
- Access to a MySQL database
Building from Source
git clone <repository-url>
cd mcp-server-mysql
cargo build --release
The compiled binary will be available at target/release/mcp-server-mysql.
From Release Package
# Extract the package
tar -xzf mcp-server-mysql-v0.2.0-linux-x86_64.tar.gz
# Move binary to system path (optional)
sudo cp mcp-server-mysql /usr/local/bin/
# Verify installation
mcp-server-mysql --version
Quick Start (5 Minutes)
Step 1: Build the Server
The binary will be at target/release/mcp-server-mysql
Step 2: Test the Connection
./target/release/mcp-server-mysql \
--host localhost \
--username root \
--password yourpassword \
--database testdb
You should see: "MCP MySQL Server started and ready to accept connections"
Step 3: Configure Claude Desktop
Edit your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:
%APPDATA%\Claude\claude_desktop_config.json
Add this configuration:
{
"mcpServers": {
"mysql": {
"command": "/absolute/path/to/mcp-server-mysql",
"args": [
"--host", "localhost",
"--port", "3306",
"--username", "your_username",
"--password", "your_password",
"--database", "your_database"
]
}
}
}
Security Note: For production use, consider using environment variables or a secure secrets management solution instead of hardcoding passwords in the configuration file.
Step 4: Restart Claude Desktop
Close and reopen Claude Desktop completely. You should see a small hammer icon indicating the MCP server is connected.
Step 5: Try it Out!
Ask Claude:
- "Can you show me the schema for the users table in my MySQL database?"
- "Query the database and show me the first 10 rows from the products table"
- "What tables are in my database?"
Usage
Command Line Arguments
mcp-server-mysql \
--host localhost \
--port 3306 \
--username your_username \
--password your_password \
--database your_database \
--allow-dangerous-queries false
Arguments Reference
| Argument | Description | Default | Required |
|---|
--host | MySQL server hostname | localhost | No |
--port | MySQL server port | 3306 | No |
--username | MySQL username | - | Yes |
--password | MySQL password | (empty) | No |
--database | Database name to connect to | - | Yes |
--allow-dangerous-queries | Allow INSERT/UPDATE/DELETE queries | false | No |
Configuration with Claude Desktop
Add this configuration to your Claude Desktop config file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"mysql": {
"command": "/path/to/mcp-server-mysql",
"args": [
"--host", "localhost",
"--port", "3306",
"--username", "your_username",
"--password", "your_password",
"--database", "your_database"
]
}
}
}
Available Tools
1. mysql (Schema Inspection)
Retrieve database schema information for tables.
Parameters:
table_name (string): Name of the table to inspect, or "all-tables" to get all table schemas
Example:
{
"table_name": "users"
}
Returns:
- Column information (name, type, nullable, defaults, keys)
- Index information
- Table constraints
2. query (SQL Execution)
Execute SQL queries on the database.
Parameters:
query (string): SQL query to execute
database (string, optional): Database name to use for this specific query
Example:
{
"query": "SELECT * FROM users WHERE active = 1 LIMIT 10",
"database": "my_database"
}
Safety:
- By default, only SELECT queries are allowed
- Use
--allow-dangerous-queries flag to enable INSERT/UPDATE/DELETE
- Dangerous keywords are blocked unless explicitly enabled
3. insert (Insert Data)
Insert data into a specified table.
Parameters:
table_name (string): Name of the table
data (object): Key-value pairs of column names and values
Example:
{
"table_name": "users",
"data": {
"username": "john_doe",
"email": "john@example.com",
"active": true
}
}
Returns: Last insert ID
4. update (Update Data)
Update data in a specified table based on conditions.
Parameters:
table_name (string): Name of the table
data (object): Key-value pairs of columns to update
conditions (object): Key-value pairs for WHERE clause
Example:
{
"table_name": "users",
"data": {
"email": "newemail@example.com",
"updated_at": "2024-01-15 10:30:00"
},
"conditions": {
"id": 123
}
}
Returns: Number of affected rows
5. delete (Delete Data)
Delete data from a specified table based on conditions.
Parameters:
table_name (string): Name of the table
conditions (object): Key-value pairs for WHERE clause
Example:
{
"table_name": "users",
"conditions": {
"id": 123
}
}
Returns: Number of affected rows
Warning: Always specify conditions to avoid deleting all rows!
Database Context Feature
The Problem
Previously, database context was not maintained between queries:
-- Query 1
USE dev_database; -- Succeeds
-- Query 2 (new connection from pool)
SELECT * FROM my_table; -- β Fails: context was lost
The Solution
Use the optional database parameter on each query:
{
"query": "SELECT * FROM my_table",
"database": "dev_database"
}
Benefits
- Explicit and Clear: Know exactly which database each query uses
- No Hidden State: Each query is independent
- Backward Compatible: Existing queries without parameter still work
- No Race Conditions: Each query gets its own connection
- Simple to Use: Just add
"database": "name" to query arguments
Usage Examples
Basic Query with Database Parameter
{
"query": "SELECT * FROM crm_sites LIMIT 10",
"database": "dev_smartConnect_za"
}
Query Without Database Parameter (Uses Default)
{
"query": "SELECT * FROM users WHERE active = 1"
}
Uses the database specified in --database startup argument.
Multiple Databases in Same Session
// Query database 1
{
"query": "SELECT COUNT(*) FROM customers",
"database": "production_db"
}
// Query database 2
{
"query": "SELECT COUNT(*) FROM test_data",
"database": "test_db"
}
Before vs After
Before (Required fully qualified names):
SELECT * FROM dev_smartConnect_za.crm_sites
JOIN dev_smartConnect_za.crm_orgs ON ...
WHERE dev_smartConnect_za.crm_sites.active = 1;
After (Clean and simple):
{
"query": "SELECT * FROM crm_sites JOIN crm_orgs ON ... WHERE active = 1",
"database": "dev_smartConnect_za"
}
Common Scenarios
Scenario 1: Single Database Project
Set default database and omit the parameter:
# Startup
--database my_project_db
# Query (no database parameter needed)
{
"query": "SELECT * FROM users"
}
Scenario 2: Multiple Database Project
Specify database for each query:
// Customer database
{ "query": "...", "database": "customers_db" }
// Orders database
{ "query": "...", "database": "orders_db" }
// Analytics database
{ "query": "...", "database": "analytics_db" }
Error Handling
Error Code -32005: Connection Acquisition Failed
Cause: Connection pool exhausted
Solution: Retry after a moment
Error Code -32006: Database Context Switch Failed
Cause: Database doesn't exist or user lacks permissions
Solution: Verify database exists and user has access
Best Practices
β
DO
- Specify database explicitly for production queries
- Use descriptive database names in your queries
- Test with
SELECT DATABASE() to verify context
- Group queries by database for clarity
β DON'T
- Mix qualified and unqualified names in the same query
- Assume persistence - specify database for each query
- Use special characters in database names if possible
- Forget to verify user permissions for all databases
Security Considerations
Read-Only Mode (Default)