MySQL MCP Server Guide: Setup and Queries
Connect MySQL databases to Model Context Protocol agents: Step-by-step configuration, read-only permissions, schema discovery, and query execution.
claude_desktop_config.json{
"mcpServers": {
"mysql": {
"command": "npx",
"args": [
"-y",
"@benborla29/mcp-server-mysql"
],
"env": {
"MYSQL_HOST": "localhost",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "",
"MYSQL_DATABASE": "mydb"
}
}
}
}Generate & Test MySQL MCP Server Config
One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.
MySQL MCP Server Guide: Setup and Queries
Connecting relational databases directly to language model agents enables engineering teams to automate schema analysis, synthesize business intelligence metrics, and diagnose application database state directly from terminal and IDE workflows. Through the Model Context Protocol (MCP), agents operating inside Claude Desktop, Cursor, or the OpenAI Codex CLI can introspect MySQL table definitions, explain query plans, and execute analytical queries without requiring developers to manually export raw CSV dumps.
However, giving language model agents direct database connectivity introduces significant reliability and security challenges. Without strict read-only role scoping, query timeouts, and connection pool sizing, an agent may inadvertently lock tables, execute unindexed Cartesian joins, or hallucinate destructive mutation statements.
This guide provides an end-to-end operational manual for deploying a secure, high-performance MySQL MCP server, including least-privilege user creation, multi-client configuration, a production TypeScript server using mysql2, JSON-RPC message traces, and troubleshooting procedures.
1. System Architecture and Protocol Mechanics
The MySQL MCP server runs as an independent local or containerized process that translates structured JSON-RPC tool invocations from the AI host into parameterized SQL queries against MySQL or MariaDB instances.
Protocol Mechanics and Safety Controls
- ▸Standard Input/Output Transport: For local desktop and CLI agents, the MCP server communicates over
stdio. All diagnostic logging and database warnings must be directed to standard error (stderr) to prevent protocol corruption. - ▸Read-Only Transaction Enforcement: The server validates statements at the application layer and executes queries through an unprivileged MySQL account restricted exclusively to
SELECToperations. - ▸Connection Pool Management: Unlike standard web applications where requests arrive concurrently from thousands of users, an MCP server handles sequential tool calls from a single agent. The server uses a compact connection pool (5–10 connections) with aggressive idle timeouts to prevent socket exhaustion.
2. Environment Prerequisites and Software Matrix
Before configuring the MySQL MCP server, verify that your environment satisfies the following requirements:
| Component | Minimum Version | Description |
|---|---|---|
| Node.js | >= 20.0.0 | Server runtime environment |
| MySQL / MariaDB | MySQL >= 8.0 / MariaDB >= 10.6 | Target database instance |
| mysql2 | >= 3.11.0 | High-performance MySQL client supporting promises and authentication |
| @modelcontextprotocol/sdk | >= 1.2.0 | Core Model Context Protocol framework |
Ensure port 3306 is accessible between your host environment and the database cluster.
3. Creating a Hardened Read-Only Database User
Never supply an administrative account (such as root) to an MCP server. Create a dedicated user account restricted strictly to reading necessary schemas:
-- 1. Create dedicated user with strong password authentication
CREATE USER 'mcp_reader'@'%' IDENTIFIED WITH caching_sha2_password BY 'Secure_Reader_Password_2026!';
-- 2. Grant SELECT privileges only on designated application databases
GRANT SELECT, SHOW VIEW ON application_db.* TO 'mcp_reader'@'%';
-- 3. Grant schema introspection rights
GRANT SELECT ON information_schema.tables TO 'mcp_reader'@'%';
GRANT SELECT ON information_schema.columns TO 'mcp_reader'@'%';
-- 4. Apply execution constraints to prevent resource starvation
ALTER USER 'mcp_reader'@'%' WITH MAX_QUERIES_PER_HOUR 5000 MAX_USER_CONNECTIONS 10;
FLUSH PRIVILEGES;4. Multi-Host Configuration Snippets
Configure your MCP clients to launch the MySQL server over stdio. Provide connection credentials via isolated environment variables.
Claude Desktop Configuration (claude_desktop_config.json)
{
"mcpServers": {
"mysql": {
"command": "node",
"args": ["/opt/mcp-servers/mysql/dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_USER": "mcp_reader",
"MYSQL_PASSWORD": "Secure_Reader_Password_2026!",
"MYSQL_DATABASE": "application_db"
}
}
}
}Cursor IDE Configuration (.cursor/mcp.json)
{
"mcpServers": {
"mysql": {
"command": "node",
"args": ["./dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_USER": "mcp_reader",
"MYSQL_PASSWORD": "Secure_Reader_Password_2026!",
"MYSQL_DATABASE": "application_db"
}
}
}
}OpenAI Codex CLI Configuration (~/.codex/config.toml)
[mcp_servers.mysql]
command = "node"
args = ["/opt/mcp-servers/mysql/dist/index.js"]
[mcp_servers.mysql.env]
MYSQL_HOST = "127.0.0.1"
MYSQL_PORT = "3306"
MYSQL_USER = "mcp_reader"
MYSQL_PASSWORD = "Secure_Reader_Password_2026!"
MYSQL_DATABASE = "application_db"5. Production TypeScript MySQL MCP Server
The following server implementation uses mysql2/promise to provide schema introspection (list_tables, describe_table) and query execution (query) with token-efficient markdown output:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import mysql from 'mysql2/promise';
const pool = mysql.createPool({
host: process.env.MYSQL_HOST || 'localhost',
port: parseInt(process.env.MYSQL_PORT || '3306', 10),
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
waitForConnections: true,
connectionLimit: 10,
maxIdle: 5,
idleTimeout: 30000,
queueLimit: 0,
charset: 'utf8mb4'
});
const server = new Server(
{ name: 'mysql-mcp-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'list_tables',
description: 'List all table names available in the current database.',
inputSchema: { type: 'object', properties: {} }
},
{
name: 'describe_table',
description: 'Retrieve column names, data types, nullability, and primary keys for a table.',
inputSchema: {
type: 'object',
properties: {
table_name: { type: 'string', description: 'Target table name' }
},
required: ['table_name']
}
},
{
name: 'query',
description: 'Execute a read-only SQL SELECT query. Maximum 200 records returned.',
inputSchema: {
type: 'object',
properties: {
sql: { type: 'string', description: 'SQL SELECT query string' }
},
required: ['sql']
}
}
]
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
if (name === 'list_tables') {
const [rows] = await pool.query('SHOW TABLES');
return {
content: [{ type: 'text', text: JSON.stringify(rows, null, 2) }]
};
}
if (name === 'describe_table') {
const tableName = args?.table_name as string;
const [rows] = await pool.query('DESCRIBE ??', [tableName]);
return {
content: [{ type: 'text', text: JSON.stringify(rows, null, 2) }]
};
}
if (name === 'query') {
const sql = (args?.sql as string).trim();
// Guardrail: Enforce SELECT only
if (!sql.toLowerCase().startsWith('select') && !sql.toLowerCase().startsWith('show')) {
return {
isError: true,
content: [{ type: 'text', text: 'Error: Only SELECT and SHOW statements are permitted.' }]
};
}
const boundedSql = sql.toLowerCase().includes('limit') ? sql : `${sql} LIMIT 200`;
const [rows]: [any[], any] = await pool.query(boundedSql);
if (rows.length === 0) {
return { content: [{ type: 'text', text: 'Query returned 0 rows.' }] };
}
const headers = Object.keys(rows[0]);
const headerLine = `| ${headers.join(' | ')} |`;
const dividerLine = `| ${headers.map(() => '---').join(' | ')} |`;
const dataLines = rows
.map(row => `| ${headers.map(h => String(row[h] ?? 'NULL')).join(' | ')} |`)
.join('\n');
return {
content: [{ type: 'text', text: `${headerLine}\n${dividerLine}\n${dataLines}` }]
};
}
throw new Error(`Unrecognized tool: ${name}`);
} catch (err: any) {
return {
isError: true,
content: [{ type: 'text', text: `Database Error: ${err.message}` }]
};
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((err) => {
process.stderr.write(`Fatal error: ${err.message}\n`);
process.exit(1);
});6. JSON-RPC 2.0 Wire Payloads
Inspecting the underlying protocol frames helps verify proper operation across client logs.
Tool Invocation Request (tools/call)
{
"jsonrpc": "2.0",
"id": "mysql-query-101",
"method": "tools/call",
"params": {
"name": "describe_table",
"arguments": {
"table_name": "orders"
}
}
}Result Payload
{
"jsonrpc": "2.0",
"id": "mysql-query-101",
"result": {
"content": [
{
"type": "text",
"text": "[\n {\"Field\": \"id\", \"Type\": \"bigint unsigned\", \"Null\": \"NO\", \"Key\": \"PRI\"},\n {\"Field\": \"total_amount\", \"Type\": \"decimal(10,2)\", \"Null\": \"NO\", \"Key\": \"\"}\n]"
}
]
}
}7. Common Errors and Production Troubleshooting
When operating the MySQL MCP server in production environments, monitor for the following failure modes:
Error: ER_ACCESS_DENIED_ERROR: Access denied for user
- ▸Root Cause: Invalid credentials or host specification mismatch. MySQL evaluates user permissions by both username and host (e.g.
'mcp_reader'@'localhost'vs'mcp_reader'@'%'). - ▸Resolution: Verify that the host definition matches the connection source, and test connectivity directly using the terminal MySQL client:
mysql -h 127.0.0.1 -u mcp_reader -p.
Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol
- ▸Root Cause: MySQL 8.0 uses
caching_sha2_passwordby default, which legacy or unbundled client libraries may fail to negotiate over unencrypted connections. - ▸Resolution: Upgrade to
mysql2version>= 3.9.0or configure your user account to negotiate modern authentication securely.
Character Encoding Corruption (Garbled Unicode Text)
- ▸Root Cause: Database tables contain UTF-8 characters (emojis, multi-byte international text) while the client connection defaults to
latin1. - ▸Resolution: Always set
charset: 'utf8mb4'in connection pool settings.
8. External Citations and Security Guardrails
Connecting language model agents to relational databases requires continuous governance:
- ▸Audit Queries: Record all incoming SQL statements with execution durations to a security log stream for compliance monitoring.
- ▸Official Standards and Repositories:
Weekly Protocol Diffs & Verified Drops
New server guides, benchmarks, and security audits. No spam. Unsubscribe anytime.
Zero marketing spam. 1-click unsubscribe anytime.
Build your full agent toolstack in the Visual Generator
Combine MySQL with databases, search APIs, and memory graphs in a single configuration file.
Did this setup guide work with your AI host?
Help test this configuration across Claude, Cursor, and Codex CLI. Be the first to report:
MySQL MCP Server Guide: Setup and Queries FAQ
What is the MySQL MCP Server Guide: Setup and Queries?
Connect MySQL databases to Model Context Protocol agents: Step-by-step configuration, read-only permissions, schema discovery, and query execution.
How do I configure MySQL MCP Server Guide: Setup and Queries in Claude Desktop or Cursor?
You can copy the configuration JSON from our guide or launch the interactive MCP Codex Config Generator at https://mcp-codex.com/generator to export valid configs in 1 click.
Can I use MySQL MCP Server Guide: Setup and Queries with the OpenAI Codex CLI?
Yes, OpenAI Codex CLI supports Model Context Protocol. You can add it directly to ~/.codex/config.toml or pass arguments to codex mcp add.
Specializing in Model Context Protocol (MCP) integrations, autonomous AI agent orchestration, and distributed developer toolchains. Researches and benchmarks production MCP client-server architectures across OpenAI Codex, Claude, and Cursor.
Related Guides
Neo4j Knowledge Graph MCP Server Guide
Connect Neo4j knowledge graphs to AI agents via MCP. Run Cypher queries, traverse entity relationships, and build structured GraphRAG pipelines.
DatabasesConnecting Turso & LibSQL Edge Databases to AI Agents using MCP
Connect globally distributed LibSQL/Turso databases to AI agents. Expose safe read-only SQL execution tools for remote data queries.
DatabasesChromaDB Vector Search MCP Server Guide
Connect ChromaDB vector search to AI agents via MCP. Build persistent semantic memory, dynamic embeddings retrieval, and production RAG tool pipelines.