/api-database-mysql
Direct MySQL database access with mysql2 driver -- connection pools, prepared statements, transactions, streaming, typed queries, error handling
$ npx -y skills add agents-inc/skills --skill api-database-mysql --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/api-database-mysql
Context preview
The summary Claude sees to decide when to auto-load this skill.
Direct MySQL database access with mysql2 driver -- connection pools, prepared statements, transactions, streaming, typed queries, error handling
SKILL.md
api-database-mysql.SKILL.mdname: api-database-mysql
description: Direct MySQL database access with mysql2 driver -- connection pools, prepared statements, transactions, streaming, typed queries, error handling
MySQL Patterns (mysql2)
> **Quick Guide:** Use **mysql2/promise** for all new code -- it provides async/await support over the mysql2 callback API. Always use `createPool()` (never `createConnection()` in production) with `execute()` for parameterized queries (prepared statements, LRU-cached). Type query results with `RowDataPacket` generics for SELECTs and `ResultSetHeader` for INSERT/UPDATE/DELETE. For transactions, acquire a dedicated connection with `pool.getConnection()`, wrap in try/finally to guarantee `connection.release()`. Never interpolate user input into SQL strings -- always use `?` placeholders. Handle `ER_DUP_ENTRY` and `ER_LOCK_DEADLOCK` explicitly in catch blocks.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST use `execute()` with `?` placeholders for ALL queries containing user input -- NEVER interpolate values into SQL strings with template literals or string concatenation)**
**(You MUST use `pool.getConnection()` for transactions and release the connection in a `finally` block -- pool convenience methods (`pool.execute()`) use a different connection per call and cannot maintain transaction state)**
**(You MUST always import from `mysql2/promise` for async/await code -- the base `mysql2` module returns callback-based objects that do not support `await`)**
**(You MUST handle the pool `error` event -- unhandled connection errors crash the Node.js process)**
</critical_requirements>
---
Examples
- [Core Patterns](examples/core.md) -- Pool setup, typed queries, prepared statements, connection lifecycle
- [Transactions](examples/transactions.md) -- Manual transactions, savepoints, deadlock retry, nested operations
- [Streaming & Batch](examples/streaming.md) -- Streaming large result sets, batch inserts, multiple statements
- [Error Handling](examples/error-handling.md) -- MySQL error codes, connection errors, retry strategies, graceful degradation
- [Configuration](examples/configuration.md) -- SSL/TLS, named placeholders, pool tuning, monitoring events
**Additional resources:**
- [reference.md](reference.md) -- Type cheat sheet, pool options, error codes, production checklist
---
**Auto-detection:** MySQL, mysql2, mysql2/promise, createPool, createConnection, RowDataPacket, ResultSetHeader, execute, prepared statement, pool.getConnection, beginTransaction, commit, rollback, ER_DUP_ENTRY, ER_LOCK_DEADLOCK, connectionLimit, SHOW TABLES, mysqldump, InnoDB, MariaDB
**When to use:**
- Direct SQL queries against MySQL or MariaDB databases
- Connection pool management for server applications
- Transactions requiring atomicity across multiple queries
- Streaming large result sets without loading all rows into memory
- Typed query results with TypeScript generics
- Batch inserts or multi-statement operations
**Key patterns covered:**
- Pool creation with `mysql2/promise` and proper configuration
- Prepared statements via `execute()` with `?` placeholders
- TypeScript generics with `RowDataPacket` and `ResultSetHeader`
- Transaction lifecycle: `getConnection` -> `beginTransaction` -> `commit`/`rollback` -> `release`
- Streaming with `connection.query().stream()` on the non-promise API
- Error handling for `ER_DUP_ENTRY`, `ER_LOCK_DEADLOCK`, connection failures
- Pool events (`acquire`, `release`, `enqueue`) for monitoring
- SSL/TLS and named placeholders configuration
**When NOT to use:**
- When your project already uses an ORM or query builder for MySQL -- use that tool's skill instead
- For in-memory caching or key-value storage (use a dedicated caching solution)
- For document databases or graph queries (wrong database type)
- For one-off CLI scripts where a single connection suffices and pool overhead is unnecessary
---
<philosophy>
Philosophy
mysql2 is a **low-level MySQL driver** -- it sends SQL to MySQL and returns typed results. It does not generate SQL, manage migrations, or handle schema changes.
**Core principles:**
1. **Pools, not connections** -- Production applications should always use `createPool()`. Pools manage connection lifecycle, handle reconnection, and prevent connection exhaustion. `createConnection()` is only appropriate for one-off scripts. 2. **Prepared statements always** -- `execute()` sends parameterized queries to MySQL's prepared statement protocol. The driver caches prepared statements in an LRU cache, so repeated queries skip the preparation step. Never use `query()` with string interpolation. 3. **Type your results** -- MySQL2's TypeScript generics (`RowDataPacket`, `ResultSetHeader`) eliminate `any` from query results. Define interfaces extending `RowDataPacket` for each table shape. 4. **Transactions need dedicated connections** -- Pool convenience methods (`pool.execute()`, `pool.query()`) may use different connections for each call. Transactions require `pool.getConnection()` to pin a single connection, with `connection.release()` in a `finally` block. 5. **Fail explicitly** -- MySQL errors carry structured `code` fields (`ER_DUP_ENTRY`, `ER_LOCK_DEADLOCK`). Check `error.code` in catch blocks rather than parsing message strings.
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Pool Setup with mysql2/promise
Create a connection pool with environment-based configuration and error handling. See [examples/core.md](examples/core.md) for the complete setup pattern.
// Good Example - Production pool setup
import mysql from "mysql2/promise";
import type { Pool } from "mysql2/promise";
const DEFAULT_CONNECTION_LIMIT = 10;
const DEFAULT_IDLE_TIMEOUT_MS = 60_000;
function createDatabasePool(): Pool {
const url = process.env.DATABRead more
name: api-database-mysql description: Direct MySQL database access with mysql2 driver -- connection pools, prepared statements, transactions, streaming, typed queries, error handling
MySQL Patterns (mysql2)
> **Quick Guide:** Use **mysql2/promise** for all new code -- it provides async/await support over the mysql2 callback API. Always use `createPool()` (never `createConnection()` in production) with `execute()` for parameterized queries (prepared statements, LRU-cached). Type query results with `RowDataPacket` generics for SELECTs and `ResultSetHeader` for INSERT/UPDATE/DELETE. For transactions, acquire a dedicated connection with `pool.getConnection()`, wrap in try/finally to guarantee `connection.release()`. Never interpolate user input into SQL strings -- always use `?` placeholders. Handle `ER_DUP_ENTRY` and `ER_LOCK_DEADLOCK` explicitly in catch blocks.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST use `execute()` with `?` placeholders for ALL queries containing user input -- NEVER interpolate values into SQL strings with template literals or string concatenation)**
**(You MUST use `pool.getConnection()` for transactions and release the connection in a `finally` block -- pool convenience methods (`pool.execute()`) use a different connection per call and cannot maintain transaction state)**
**(You MUST always import from `mysql2/promise` for async/await code -- the base `mysql2` module returns callback-based objects that do not support `await`)**
**(You MUST handle the pool `error` event -- unhandled connection errors crash the Node.js process)**
</critical_requirements>
---
Examples
- [Core Patterns](examples/core.md) -- Pool setup, typed queries, prepared statements, connection lifecycle
- [Transactions](examples/transactions.md) -- Manual transactions, savepoints, deadlock retry, nested operations
- [Streaming & Batch](examples/streaming.md) -- Streaming large result sets, batch inserts, multiple statements
- [Error Handling](examples/error-handling.md) -- MySQL error codes, connection errors, retry strategies, graceful degradation
- [Configuration](examples/configuration.md) -- SSL/TLS, named placeholders, pool tuning, monitoring events
**Additional resources:**
- [reference.md](reference.md) -- Type cheat sheet, pool options, error codes, production checklist
---
**Auto-detection:** MySQL, mysql2, mysql2/promise, createPool, createConnection, RowDataPacket, ResultSetHeader, execute, prepared statement, pool.getConnection, beginTransaction, commit, rollback, ER_DUP_ENTRY, ER_LOCK_DEADLOCK, connectionLimit, SHOW TABLES, mysqldump, InnoDB, MariaDB
**When to use:**
- Direct SQL queries against MySQL or MariaDB databases
- Connection pool management for server applications
- Transactions requiring atomicity across multiple queries
- Streaming large result sets without loading all rows into memory
- Typed query results with TypeScript generics
- Batch inserts or multi-statement operations
**Key patterns covered:**
- Pool creation with `mysql2/promise` and proper configuration
- Prepared statements via `execute()` with `?` placeholders
- TypeScript generics with `RowDataPacket` and `ResultSetHeader`
- Transaction lifecycle: `getConnection` -> `beginTransaction` -> `commit`/`rollback` -> `release`
- Streaming with `connection.query().stream()` on the non-promise API
- Error handling for `ER_DUP_ENTRY`, `ER_LOCK_DEADLOCK`, connection failures
- Pool events (`acquire`, `release`, `enqueue`) for monitoring
- SSL/TLS and named placeholders configuration
**When NOT to use:**
- When your project already uses an ORM or query builder for MySQL -- use that tool's skill instead
- For in-memory caching or key-value storage (use a dedicated caching solution)
- For document databases or graph queries (wrong database type)
- For one-off CLI scripts where a single connection suffices and pool overhead is unnecessary
---
<philosophy>
Philosophy
mysql2 is a **low-level MySQL driver** -- it sends SQL to MySQL and returns typed results. It does not generate SQL, manage migrations, or handle schema changes.
**Core principles:**
1. **Pools, not connections** -- Production applications should always use `createPool()`. Pools manage connection lifecycle, handle reconnection, and prevent connection exhaustion. `createConnection()` is only appropriate for one-off scripts. 2. **Prepared statements always** -- `execute()` sends parameterized queries to MySQL's prepared statement protocol. The driver caches prepared statements in an LRU cache, so repeated queries skip the preparation step. Never use `query()` with string interpolation. 3. **Type your results** -- MySQL2's TypeScript generics (`RowDataPacket`, `ResultSetHeader`) eliminate `any` from query results. Define interfaces extending `RowDataPacket` for each table shape. 4. **Transactions need dedicated connections** -- Pool convenience methods (`pool.execute()`, `pool.query()`) may use different connections for each call. Transactions require `pool.getConnection()` to pin a single connection, with `connection.release()` in a `finally` block. 5. **Fail explicitly** -- MySQL errors carry structured `code` fields (`ER_DUP_ENTRY`, `ER_LOCK_DEADLOCK`). Check `error.code` in catch blocks rather than parsing message strings.
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Pool Setup with mysql2/promise
Create a connection pool with environment-based configuration and error handling. See [examples/core.md](examples/core.md) for the complete setup pattern.
// Good Example - Production pool setup
import mysql from "mysql2/promise";
import type { Pool } from "mysql2/promise";
const DEFAULT_CONNECTION_LIMIT = 10;
const DEFAULT_IDLE_TIMEOUT_MS = 60_000;
function createDatabasePool(): Pool {
const url = process.env.DATABShowing the first part of this file.
The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Other skills on agents-inc-skills.
- /ai-infrastructure-huggingface-inference
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints
Open skill - /ai-infrastructure-litellm
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment
Open skill - /ai-infrastructure-modal
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Open skill - /ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
Open skill - /ai-infrastructure-replicate
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Open skill - /ai-infrastructure-together-ai
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints
Open skill

