How do prepared statements prevent SQL injection?
Short answer
Prepared statements send the query template to the database first, with placeholders, so the structure is fixed before any user data arrives. Parameters are then bound as pure data and can never be parsed as SQL — so input like ' OR 1=1 is treated as a literal string, not code. This separation is the canonical, reliable fix for injection.
Prepared statements (parameterized queries) are the canonical defense against SQL injection because they attack the root cause: SQL injection only exists because data and code travel together in one string. Prepared statements split them apart.
How the separation works
The query is sent to the database in two phases:
- Prepare. The application sends the query template with placeholders, e.g.
SELECT * FROM users WHERE email = ?. The database parses, compiles, and plans this statement before seeing any user input. The structure is now locked. - Bind and execute. The user-supplied values are sent separately and bound to the placeholders as typed data. They are never re-parsed as SQL.
So if an attacker submits ' OR 1=1 --, the database treats that entire string as a literal value to compare against the email column. It looks for a user whose email is literally ' OR 1=1 --, finds none, and returns nothing. The payload never becomes part of the query logic.
Why escaping is the weaker alternative
Manual escaping tries to neutralize dangerous characters in a concatenated string — but it is easy to get wrong (charset issues, missed contexts, numeric fields without quotes). Prepared statements remove the entire class of mistake.
Where they fall short
Placeholders only work for data values, not for identifiers — you cannot parameterize a table name, column name, or ORDER BY direction. If those must be dynamic, you must use a strict allowlist mapping user input to known-good identifiers. ORMs generally use prepared statements under the hood, but raw-SQL escape hatches can reintroduce injection.
Interviewers look for the "structure compiled before data arrives" explanation, the concrete ' OR 1=1 example becoming a literal, and awareness of the identifier limitation requiring allowlists.
Likely follow-ups
- Why can't you use a placeholder for a table or column name?
- How does an ORM relate to prepared statements?
- When is escaping or allowlisting still necessary?