MySQL Prepared Statements
Prepared statements let you write a SQL query once with placeholders and execute it repeatedly with different values, safely and efficiently.
What a Prepared Statement Does
A prepared statement is a query template sent to MySQL with placeholders (typically written as ?) standing in for values. MySQL parses and plans the query structure once, then you supply the actual values in a separate step to execute it. Because the values are bound as data rather than inserted into the SQL text, they can never change the query's structure — this is what makes prepared statements the standard defense against SQL injection.
Prepared Statements at the SQL Level
MySQL supports prepared statements directly in SQL using PREPARE, EXECUTE, and DEALLOCATE PREPARE, useful inside stored procedures or ad-hoc admin scripts.
Raw SQL prepared statement
PREPARE find_user FROM 'SELECT id, email FROM users WHERE id = ?';
SET @user_id = 42;
EXECUTE find_user USING @user_id;
DEALLOCATE PREPARE find_user;Prepared Statements from Application Code
In practice, most prepared statements are issued through a driver or ORM, which handles PREPARE/EXECUTE behind a simple API. The placeholder syntax differs slightly by driver: mysql2 for Node.js uses ?, while PHP's PDO supports both ? and named placeholders like :id.
Node.js with mysql2 — positional placeholders
const [rows] = await connection.execute(
'SELECT id, email FROM users WHERE id = ? AND status = ?',
[userId, 'active']
);PHP with PDO — named placeholders
$stmt = $pdo->prepare('SELECT id, email FROM users WHERE id = :id AND status = :status');
$stmt->execute(['id' => $userId, 'status' => 'active']);
$user = $stmt->fetch();Reusing a Prepared Statement
One of the practical benefits of prepared statements, beyond security, is performance when the same query shape runs many times: MySQL can reuse the parsed execution plan instead of re-parsing identical SQL text on every call.
Executing the same prepared statement with different values
PREPARE insert_log FROM 'INSERT INTO audit_log (user_id, action) VALUES (?, ?)';
SET @uid = 7, @act = 'login';
EXECUTE insert_log USING @uid, @act;
SET @uid = 8, @act = 'logout';
EXECUTE insert_log USING @uid, @act;
DEALLOCATE PREPARE insert_log;- Placeholders (? or :name) mark where a value goes; MySQL treats bound values strictly as data, never as SQL syntax.
- The query's structure is parsed once and can be executed multiple times with different bound values.
- Most application code never calls PREPARE/EXECUTE directly — the database driver does it under the hood.
- Always deallocate raw SQL prepared statements when done, or let the session end, to free server resources.
- Prepared statements are the standard, reliable defense against SQL injection — safer than manual input escaping.
Exercise: MySQL Prepared Statements
What is the basic sequence when using a prepared statement?