ℹ️
MariaDB System & Info Functions MariaDB Complete reference for MariaDB system and info functions covering VERSION(), DATABASE(), USER(), CONNECTION_ID(), LAST_INSERT_ID(), FOUND_ROWS(), and CURRENT_ROLE(). Every function includes syntax, use cases, and notes on session-scoped vs global behaviour. Updated for MariaDB 11.x.
27 functions
What are MariaDB System & Info Functions? MariaDB system information functions return metadata about the current server session, database, and user. LAST_INSERT_ID() returns the AUTO_INCREMENT value generated by the most recent INSERT, FOUND_ROWS() returns the number of rows that would have been returned by the last SELECT without LIMIT, and ROW_COUNT() returns the number of rows affected by the last INSERT, UPDATE, DELETE, or REPLACE. These are frequently used in stored procedures and application code to handle post-insert logic.
VERSION → VARCHAR Returns the MariaDB server version string, always including the '-MariaDB' suffix.
Examples Get server version
sql copy
SELECT VERSION ();→ -- 10.11.4-MariaDB
System variable alternative
sql copy
SELECT @@version ;→ -- 10.11.4-MariaDB
Confirm running MariaDB
sql copy
SELECT VERSION () LIKE '%MariaDB%' ;→ -- 1
Extract major version
sql copy
SELECT SUBSTRING_INDEX (VERSION (), '.' , 1 ) AS major ;→ -- 10
Store in variable
sql copy
SELECT VERSION () INTO @v ; SELECT @v ;→ -- 10.11.4-MariaDB
⚠ Anti-Pattern — Checking for MySQL with VERSION()
Checking VERSION() LIKE 'MySQL%' will fail on MariaDB. The string contains '-MariaDB' suffix.
✓ Instead: Check VERSION() LIKE '%MariaDB%' or use @@version_comment.
◆ MariaDB Note
Always includes '-MariaDB' in the version string.
⇄ vs MySQL: MySQL VERSION() returns '8.x.x' without '-MariaDB' suffix.
⇄ vs PostgreSQL: PostgreSQL uses version() or current_setting('server_version').
DATABASE → VARCHAR Returns the name of the currently selected database, or NULL if no database is selected.
Examples Current database name
sql copy
SELECT DATABASE ();→ -- mydb
Check if database selected
sql copy
SELECT DATABASE () IS NULL ;→ -- 0
After USE statement
sql copy
USE information_schema ; SELECT DATABASE ();→ -- information_schema
Cross-reference with catalog
sql copy
SELECT SCHEMA_NAME FROM information_schema .SCHEMATA WHERE SCHEMA_NAME = DATABASE ();→ -- mydb
Save current DB to variable
sql copy
SET @db = DATABASE (); SELECT @db ;→ -- mydb
⚠ Anti-Pattern — Hardcoding database name in queries
Using a literal database name in queries makes them non-portable across environments.
✓ Instead: Use DATABASE() to dynamically reference the current database in procedures.
◆ MariaDB Note
Synonym for SCHEMA(). Returns NULL if no database is selected.
⇄ vs MySQL: Identical behavior in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses current_database().
SCHEMA → VARCHAR Synonym for DATABASE(). Returns the name of the currently selected database.
Examples Current schema/database name
sql copy
SELECT SCHEMA ();→ -- mydb
SCHEMA and DATABASE are identical
sql copy
SELECT SCHEMA () = DATABASE ();→ -- 1
Fallback if no DB selected
sql copy
SELECT COALESCE (SCHEMA (), 'none' ) AS db ;→ -- mydb
After switching database
sql copy
USE test ; SELECT SCHEMA ();→ -- test
List tables in current DB
sql copy
SELECT TABLE_NAME FROM information_schema .TABLES WHERE TABLE_SCHEMA = SCHEMA ();→ -- (list of tables)
⚠ Anti-Pattern — Mixing SCHEMA() and DATABASE() inconsistently
Using both interchangeably without convention can confuse readers.
✓ Instead: Pick one and use it consistently; SCHEMA() is closer to standard SQL.
◆ MariaDB Note
Exact synonym for DATABASE().
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses current_schema() or current_database().
USER → VARCHAR Returns the current MariaDB user and host as 'user@host', representing the connection's authentication credentials.
Examples Current user and host
sql copy
SELECT USER ();→ -- admin@localhost
Extract just the username
sql copy
SELECT SUBSTRING_INDEX (USER (), '@' , 1 ) AS username ;→ -- admin
Extract just the host
sql copy
SELECT SUBSTRING_INDEX (USER (), '@' , - 1 ) AS host ;→ -- localhost
Compare to current_user
sql copy
SELECT USER () = CURRENT_USER ();→ -- 1 (usually)
DUAL table form
sql copy
SELECT USER () FROM DUAL ;→ -- admin@localhost
⚠ Anti-Pattern — Using USER() for permission checks
USER() returns the login credentials, not the effective privilege account. Security checks based on USER() can be bypassed via proxy users.
✓ Instead: Use CURRENT_USER() which reflects the actual privilege account.
◆ MariaDB Note
Returns 'user@host'. May differ from CURRENT_USER() when using definer-context or proxy accounts.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses session_user or current_user.
CURRENT_USER → VARCHAR Returns the username and hostname combination that was matched in the grant tables for the current session, reflecting the effective privilege account.
Signatures CURRENT_USER()
CURRENT_USER
Examples Matched grant account
sql copy
SELECT CURRENT_USER ();→ -- admin@%
Without parentheses (standard SQL)
sql copy
SELECT CURRENT_USER ;→ -- admin@%
May differ with wildcards
sql copy
SELECT USER (), CURRENT_USER ();→ -- admin@localhost | admin@%
Show own grants
sql copy
SHOW GRANTS FOR CURRENT_USER ();→ -- GRANT ... TO 'admin'@'%'
Store in variable
sql copy
SELECT CURRENT_USER () INTO @cu ;→ -- admin@%
⚠ Anti-Pattern — Confusing USER() and CURRENT_USER()
USER() is what you logged in as; CURRENT_USER() is the grant row matched. For security decisions, always use CURRENT_USER().
✓ Instead: Use CURRENT_USER() for privilege-related logic.
◆ MariaDB Note
Supports both CURRENT_USER and CURRENT_USER() forms per SQL standard.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses current_user (keyword, no parentheses needed).
SESSION_USER → VARCHAR Synonym for USER(). Returns the current client user and hostname used for authentication.
Examples Session user
sql copy
SELECT SESSION_USER ();→ -- admin@localhost
SESSION_USER and USER are identical
sql copy
SELECT SESSION_USER () = USER ();→ -- 1
Extract username part
sql copy
SELECT SUBSTRING_INDEX (SESSION_USER (), '@' , 1 );→ -- admin
DUAL table form
sql copy
SELECT SESSION_USER () FROM DUAL ;→ -- admin@localhost
Embed in view
sql copy
CREATE VIEW session_info AS SELECT SESSION_USER () AS login_user ;→ -- View created
⚠ Anti-Pattern — Using SESSION_USER instead of CURRENT_USER for access control
SESSION_USER returns the login identity, not the privilege-matched account. Proxy users can log in as one user but match a different grant.
✓ Instead: Use CURRENT_USER() for access control decisions.
◆ MariaDB Note
Exact synonym for USER().
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses session_user.
SYSTEM_USER → VARCHAR Synonym for USER(). Returns the current authenticated user and host. Provided for SQL standard compatibility.
Examples System user
sql copy
SELECT SYSTEM_USER ();→ -- admin@localhost
All three user functions agree
sql copy
SELECT SYSTEM_USER () = SESSION_USER ();→ -- 1
Synonym confirmation
sql copy
SELECT SYSTEM_USER () = USER ();→ -- 1
Audit logging
sql copy
INSERT INTO audit_log (action , who ) VALUES ('login' , SYSTEM_USER ());→ -- 1 row affected
Extract connecting host
sql copy
SELECT SUBSTRING_INDEX (SYSTEM_USER (), '@' , - 1 ) AS client_host ;→ -- localhost
⚠ Anti-Pattern — Assuming SYSTEM_USER() returns an OS-level user
Despite the name, SYSTEM_USER() in MariaDB returns the database login user, not the operating system user running the server process.
✓ Instead: To get the OS user, query @@global.secure_file_priv or use external tools.
◆ MariaDB Note
Exact synonym for USER() and SESSION_USER().
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses session_user.
CONNECTION_ID → BIGINT UNSIGNED Returns the unique thread (connection) ID for the current client session. Useful for debugging, locking, and kill commands.
Examples Current connection thread ID
sql copy
SELECT CONNECTION_ID ();→ -- 42
Find self in process list
sql copy
SHOW PROCESSLIST ;→ -- (includes row with Id = CONNECTION_ID())
Query own process info
sql copy
SELECT * FROM information_schema .PROCESSLIST WHERE ID = CONNECTION_ID ();→ -- (current session row)
Kill own running query
sql copy
SELECT CONNECTION_ID () INTO @cid ; KILL QUERY @cid ;→ -- (kills own query)
Log connection ID
sql copy
INSERT INTO session_log (conn_id , ts ) VALUES (CONNECTION_ID (), NOW ());→ -- 1 row affected
⚠ Anti-Pattern — Using CONNECTION_ID() as a globally unique row ID
Connection IDs are reused after a connection closes. Using them as a permanent unique identifier in tables can cause collisions.
✓ Instead: Use UUID() or an AUTO_INCREMENT column for permanent unique identifiers.
◆ MariaDB Note
Each new client connection gets a unique, incrementing thread ID.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses pg_backend_pid().
LAST_INSERT_ID → BIGINT UNSIGNED Returns the AUTO_INCREMENT value generated by the most recent INSERT statement in the current session, or sets a custom value for subsequent calls.
Signatures LAST_INSERT_ID()
LAST_INSERT_ID(expr)
Parameters Parameter Type Description expr BIGINT If supplied, sets the return value for subsequent LAST_INSERT_ID() calls without performing an actual insert.
Examples ID of just-inserted row
sql copy
INSERT INTO orders (product ) VALUES ('Widget' ); SELECT LAST_INSERT_ID ();→ -- 101
Bulk insert returns first ID
sql copy
INSERT INTO t (a ) VALUES (1 ),(2 ),(3 ); SELECT LAST_INSERT_ID ();→ -- (ID of first inserted row)
Manually set the value
sql copy
SELECT LAST_INSERT_ID (42 ); SELECT LAST_INSERT_ID ();→ -- 42
Atomic counter pattern
sql copy
UPDATE counters SET n = LAST_INSERT_ID (n + 1 ) WHERE name = 'hits' ; SELECT LAST_INSERT_ID ();→ -- (incremented value)
System variable alternative
sql copy
SELECT @@last_insert_id ;→ -- 101
⚠ Anti-Pattern — Assuming LAST_INSERT_ID() works across sessions
LAST_INSERT_ID() is session-specific. Another connection's inserts do not affect your session's value.
✓ Instead: Always call LAST_INSERT_ID() in the same session immediately after the INSERT.
◆ MariaDB Note
The two-argument form LAST_INSERT_ID(expr) is useful for implementing atomic counters in a single UPDATE statement.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses RETURNING id clause or lastval() / currval().
ROW_COUNT → BIGINT Returns the number of rows affected by the most recent INSERT, UPDATE, DELETE, or REPLACE statement. Returns -1 for SELECT or statements that produce a result set.
Examples Rows deleted
sql copy
DELETE FROM logs WHERE created_at < '2024-01-01' ; SELECT ROW_COUNT ();→ -- 1500
Rows updated
sql copy
UPDATE users SET active = 0 WHERE last_login < NOW () - INTERVAL 1 YEAR ; SELECT ROW_COUNT ();→ -- 23
Rows inserted
sql copy
INSERT INTO t VALUES (1 ),(2 ),(3 ); SELECT ROW_COUNT ();→ -- 3
SELECT always returns -1
sql copy
SELECT 1 ; SELECT ROW_COUNT ();→ -- -1
After stored procedure
sql copy
CALL some_proc (); SELECT ROW_COUNT ();→ -- (rows from last DML in proc)
⚠ Anti-Pattern — Calling ROW_COUNT() after a SELECT
ROW_COUNT() returns -1 after a SELECT statement. It only reflects DML operations.
✓ Instead: Use FOUND_ROWS() or COUNT(*) to count SELECT results.
◆ MariaDB Note
Returns -1 for SELECT; 0 or positive for DML. The CLIENT_FOUND_ROWS connection flag changes UPDATE counting behavior.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses GET DIAGNOSTICS row_count in PL/pgSQL, or check the command tag.
FOUND_ROWS MySQL deprecated in 8.0; MariaDB retains full support. → BIGINT Returns the number of rows that the preceding SELECT with SQL_CALC_FOUND_ROWS would have returned without the LIMIT clause. Used for pagination to get total result count in one round-trip.
Examples Total rows ignoring LIMIT
sql copy
SELECT SQL_CALC_FOUND_ROWS * FROM articles LIMIT 10 ; SELECT FOUND_ROWS ();→ -- 342
Pagination: total count
sql copy
SELECT SQL_CALC_FOUND_ROWS id FROM products WHERE active = 1 LIMIT 20 OFFSET 40 ; SELECT FOUND_ROWS ();→ -- 150
Without SQL_CALC_FOUND_ROWS returns rows in last result
sql copy
SELECT * FROM t ; SELECT FOUND_ROWS ();→ -- (same as ROW_COUNT of resultset)
Zero results
sql copy
SELECT SQL_CALC_FOUND_ROWS * FROM t WHERE 1 = 0 LIMIT 10 ; SELECT FOUND_ROWS ();→ -- 0
Store total for use in procedure
sql copy
SELECT FOUND_ROWS () INTO @total ;→ -- @total = 342
⚠ Anti-Pattern — Using FOUND_ROWS() without SQL_CALC_FOUND_ROWS
Without the SQL_CALC_FOUND_ROWS hint, FOUND_ROWS() just returns the number of rows in the last result set, not the full count without LIMIT.
✓ Instead: Always pair FOUND_ROWS() with SELECT SQL_CALC_FOUND_ROWS ... LIMIT n.
◆ MariaDB Note
Not deprecated in MariaDB. Actively maintained and preferred for pagination in many MariaDB applications.
⇄ vs MySQL: MySQL 8.0 deprecated SQL_CALC_FOUND_ROWS and FOUND_ROWS(). MariaDB keeps them active and has no deprecation plan.
⇄ vs PostgreSQL: PostgreSQL has no direct equivalent; use a CTE with COUNT(*) or a window function.
BENCHMARK → INT Executes an expression a specified number of times and returns 0. Used to measure the performance/speed of scalar expressions.
Parameters Parameter Type Description count BIGINT UNSIGNED Number of times to evaluate the expression. expr any scalar The scalar expression to evaluate repeatedly.
Examples Benchmark MD5 hashing
sql copy
SELECT BENCHMARK (1000000 , MD5 ('hello' ));→ -- 0 (check elapsed time)
Benchmark encryption
sql copy
SELECT BENCHMARK (500000 , AES_ENCRYPT ('text' , 'key' ));→ -- 0
Baseline arithmetic benchmark
sql copy
SELECT BENCHMARK (1000000 , 1+1 );→ -- 0
Compare SHA2 cost
sql copy
SELECT BENCHMARK (100000 , SHA2 ('password' , 256 ));→ -- 0
Benchmark a subquery (use low count)
sql copy
SELECT BENCHMARK (1000 , (SELECT COUNT (* ) FROM large_table ));→ -- 0
⚠ Anti-Pattern — Using BENCHMARK() with very high counts on expensive queries
Running BENCHMARK(1000000, complex_subquery) can lock up your server. Subqueries are re-executed each iteration.
✓ Instead: Use small counts (100–10000) for subqueries, or benchmark with scalar built-in functions only.
◆ MariaDB Note
Returns 0, not timing data. Timing is observed via client elapsed time.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL has no built-in BENCHMARK(); use pgbench or EXPLAIN ANALYZE.
CHARSET → VARCHAR Returns the character set of a string argument. Reflects the character set encoding of the given value.
Parameters Parameter Type Description str VARCHAR/any The string value whose character set is to be returned.
Examples Default client charset
sql copy
SELECT CHARSET ('hello' );→ -- utf8mb4
After CONVERT
sql copy
SELECT CHARSET (CONVERT ('hello' USING latin1 ));→ -- latin1
System function result charset
sql copy
SELECT CHARSET (USER ());→ -- utf8mb3
Check column charset
sql copy
SELECT col , CHARSET (col ) FROM t LIMIT 1 ;→ -- (col value) | utf8mb4
Charset introducer
sql copy
SELECT CHARSET (_utf8mb4 'test' );→ -- utf8mb4
⚠ Anti-Pattern — Assuming all strings have the same charset
Mixing charsets (e.g., utf8mb3 and utf8mb4) in JOINs or comparisons can cause implicit conversions and index misses.
✓ Instead: Use CHARSET() to diagnose, then standardize columns to utf8mb4.
◆ MariaDB Note
Returns the character set name as a string.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL does not have a CHARSET() function; use pg_catalog functions.
COERCIBILITY → INT Returns the collation coercibility value of a string argument. The coercibility value determines which collation wins when two strings of different collations are compared.
Parameters Parameter Type Description str VARCHAR/any The string expression whose coercibility is checked.
Examples Literal string = coercibility 4
sql copy
SELECT COERCIBILITY ('hello' );→ -- 4
System function = coercibility 3
sql copy
SELECT COERCIBILITY (USER ());→ -- 3
Column = coercibility 2
sql copy
SELECT COERCIBILITY (col ) FROM t LIMIT 1 ;→ -- 2
Explicit COLLATE = coercibility 0
sql copy
SELECT COERCIBILITY ('x' COLLATE utf8mb4_bin );→ -- 0
NULL = coercibility 6 (ignorable)
sql copy
SELECT COERCIBILITY (NULL );→ -- 6
⚠ Anti-Pattern — Ignoring coercibility when diagnosing collation errors
When you get 'Illegal mix of collations', not knowing the coercibility of each side makes the error hard to fix.
✓ Instead: Run SELECT COERCIBILITY(expr) on both sides to understand which should be cast.
◆ MariaDB Note
Scale: 0 (explicit COLLATE) < 1 (no collation) < 2 (column) < 3 (system func) < 4 (literal) < 5 (numeric/temporal) < 6 (NULL).
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL handles collation differently; no direct COERCIBILITY() equivalent.
COLLATION → VARCHAR Returns the collation name of the given string argument.
Parameters Parameter Type Description str VARCHAR/any The string expression whose collation is to be returned.
Examples Default collation for literal
sql copy
SELECT COLLATION ('hello' );→ -- utf8mb4_general_ci
Collation of a table column
sql copy
SELECT COLLATION (col ) FROM t LIMIT 1 ;→ -- utf8mb4_unicode_ci
After CONVERT
sql copy
SELECT COLLATION (CONVERT ('hi' USING utf8mb4 ));→ -- utf8mb4_general_ci
Explicit collation
sql copy
SELECT COLLATION ('x' COLLATE utf8mb4_bin );→ -- utf8mb4_bin
System function collation
sql copy
SELECT COLLATION (USER ());→ -- utf8mb3_general_ci
⚠ Anti-Pattern — Assuming columns are case-insensitive
A column with _bin or _cs collation will treat 'Hello' and 'hello' as different values.
✓ Instead: Use COLLATION(col) to check, then add a COLLATE clause if you need to override.
◆ MariaDB Note
Returns the full collation name including charset prefix.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL does not have a COLLATION() function; use pg_attribute or information_schema.
CURRENT_ROLE Available since MariaDB 10.0.5. → VARCHAR Returns the currently active role(s) for the session, or NONE if no role is set. MariaDB roles were introduced in 10.0.5.
Examples No role currently active
sql copy
SELECT CURRENT_ROLE ();→ -- NONE
After activating a role
sql copy
SET ROLE analyst ; SELECT CURRENT_ROLE ();→ -- analyst
Activate all granted roles
sql copy
SET ROLE ALL ; SELECT CURRENT_ROLE ();→ -- (all granted roles)
Set default role
sql copy
SET DEFAULT ROLE analyst FOR 'bob' @'%' ; SELECT CURRENT_ROLE ();→ -- analyst (on next login)
Store role in variable
sql copy
SELECT CURRENT_ROLE () INTO @role ; SELECT @role ;→ -- analyst
⚠ Anti-Pattern — Expecting CURRENT_ROLE() to auto-activate roles
Even if a user has been granted a role, CURRENT_ROLE() returns NONE unless SET ROLE or SET DEFAULT ROLE has been applied.
✓ Instead: Use SET DEFAULT ROLE for automatic activation, or SET ROLE at session start.
◆ MariaDB Note
Roles introduced in MariaDB 10.0.5. MySQL has a different role activation model.
⇄ vs MySQL: MySQL 8.0 added roles but uses @@role_xxx variables; behavior differs subtly.
⇄ vs PostgreSQL: PostgreSQL uses current_role (SQL keyword).
DEFAULT → varies Returns the default value defined for a table column. Used in INSERT/UPDATE statements to explicitly request the column's DEFAULT value.
Parameters Parameter Type Description col_name column reference The table column whose default value is to be retrieved.
Examples Show default for a timestamp column
sql copy
SELECT DEFAULT (created_at ) FROM orders LIMIT 1 ;→ -- CURRENT_TIMESTAMP
Insert using column default
sql copy
INSERT INTO orders (status ) VALUES (DEFAULT (status ));→ -- 1 row affected
Reset column to default
sql copy
UPDATE orders SET priority = DEFAULT (priority ) WHERE id = 5 ;→ -- 1 row affected
Numeric column default
sql copy
SELECT DEFAULT (stock ) FROM products LIMIT 1 ;→ -- 0
Compare value to default
sql copy
SELECT col , DEFAULT (col ) FROM t LIMIT 3 ;→ -- (value | default_val)
⚠ Anti-Pattern — Using DEFAULT(col) on columns without a defined default
Calling DEFAULT() on a column that has no DEFAULT clause results in an error.
✓ Instead: Check information_schema.COLUMNS for COLUMN_DEFAULT before using DEFAULT().
◆ MariaDB Note
Can be used in both DML and SELECT contexts.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses column_default from information_schema.columns; no DEFAULT() function.
GET_LOCK → INT Acquires a named advisory lock. Returns 1 if the lock was obtained, 0 if timed out, NULL on error. In MariaDB, multiple named locks per session are supported simultaneously.
Parameters Parameter Type Description str VARCHAR The name of the advisory lock to acquire. timeout INT Number of seconds to wait for the lock. Use -1 for indefinite wait, 0 for immediate (no wait).
Examples Acquired within 10 seconds
sql copy
SELECT GET_LOCK ('my_task' , 10 );→ -- 1
Already locked, no wait
sql copy
SELECT GET_LOCK ('my_task' , 0 );→ -- 0
Multiple locks in one session
sql copy
SELECT GET_LOCK ('lock_a' , 5 ), GET_LOCK ('lock_b' , 5 );→ -- 1 | 1
Wait forever for lock
sql copy
DO GET_LOCK ('import_job' , - 1 );→ -- (waits indefinitely)
Check before proceeding
sql copy
SELECT GET_LOCK ('task' , 30 ) INTO @got ; IF @got = 1 THEN /* do work */ END IF ;→ -- conditional logic
⚠ Anti-Pattern — Forgetting to release advisory locks
Locks held with GET_LOCK() are automatically released when the session ends, but if you hold them through long operations, other sessions block. Not releasing explicitly causes unnecessary waits.
✓ Instead: Always call RELEASE_LOCK() when the critical section is complete, or use RELEASE_ALL_LOCKS().
◆ MariaDB Note
Multiple simultaneous named locks per session are natively supported.
⇄ vs MySQL: MySQL 5.7 and earlier could only hold one named lock per session; MySQL 8.0+ supports multiple. MariaDB has always (since 10.0) supported multiple.
⇄ vs PostgreSQL: PostgreSQL uses pg_advisory_lock() / pg_advisory_unlock().
RELEASE_LOCK → INT Releases the named advisory lock acquired with GET_LOCK(). Returns 1 if the lock was released, 0 if the lock was not held by this thread, NULL if the lock does not exist.
Parameters Parameter Type Description str VARCHAR The name of the advisory lock to release.
Examples Successfully released
sql copy
SELECT RELEASE_LOCK ('my_task' );→ -- 1
Lock does not exist
sql copy
SELECT RELEASE_LOCK ('nonexistent_lock' );→ -- NULL
Not held by this thread
sql copy
SELECT RELEASE_LOCK ('other_sessions_lock' );→ -- 0
Acquire then release pattern
sql copy
SELECT GET_LOCK ('job' , 10 ); /* work */ SELECT RELEASE_LOCK ('job' );→ -- 1 | 1
Release multiple locks
sql copy
SELECT RELEASE_LOCK ('a' ), RELEASE_LOCK ('b' );→ -- 1 | 1
⚠ Anti-Pattern — Releasing a lock from a different session
RELEASE_LOCK() can only release locks held by the current session. Attempting to release another session's lock returns 0 (not an error), which may mislead callers into thinking the resource is free.
✓ Instead: Use IS_USED_LOCK() to check which connection holds the lock before attempting release.
◆ MariaDB Note
Supports releasing individual named locks from a multi-lock session.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses pg_advisory_unlock().
IS_FREE_LOCK → INT Checks whether the named advisory lock is free (not held by any session). Returns 1 if free, 0 if in use, NULL if an error occurred.
Parameters Parameter Type Description str VARCHAR The name of the advisory lock to check.
Examples Lock is not held
sql copy
SELECT IS_FREE_LOCK ('my_task' );→ -- 1
After acquiring, no longer free
sql copy
SELECT GET_LOCK ('my_task' ,0 ); SELECT IS_FREE_LOCK ('my_task' );→ -- 1 | 0
Check before trying to acquire
sql copy
SELECT IS_FREE_LOCK ('import_job' ) AS available ;→ -- 1
Polling pattern (use with caution)
sql copy
WHILE IS_FREE_LOCK ('resource' ) = 0 DO SELECT SLEEP (0.1 ); END WHILE ;→ -- (busy wait loop)
Human-readable status
sql copy
SELECT IF (IS_FREE_LOCK ('task' ), 'Available' , 'Busy' ) AS status ;→ -- Available
⚠ Anti-Pattern — TOCTOU race between IS_FREE_LOCK and GET_LOCK
Checking IS_FREE_LOCK() then calling GET_LOCK() is not atomic. Another session can grab the lock between the two calls.
✓ Instead: Call GET_LOCK() with timeout=0 directly; check the return value for 1 (acquired) or 0 (already locked).
◆ MariaDB Note
Returns NULL on error (e.g., invalid lock name).
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses pg_try_advisory_lock() for non-blocking acquisition.
IS_USED_LOCK → BIGINT UNSIGNED Returns the connection ID of the session that holds the named advisory lock, or NULL if the lock is not held.
Parameters Parameter Type Description str VARCHAR The name of the advisory lock to check.
Examples Lock is free
sql copy
SELECT IS_USED_LOCK ('my_task' );→ -- NULL
Returns holder connection ID
sql copy
SELECT GET_LOCK ('my_task' ,0 ); SELECT IS_USED_LOCK ('my_task' );→ -- 42
Check if current session holds it
sql copy
SELECT IS_USED_LOCK ('import' ) = CONNECTION_ID () AS i_hold_it ;→ -- 1
Identify the blocking session
sql copy
SELECT * FROM information_schema .PROCESSLIST WHERE ID = IS_USED_LOCK ('task' );→ -- (holder's process info)
Descriptive status
sql copy
SELECT IF (IS_USED_LOCK ('job' ) IS NULL , 'Free' , CONCAT ('Held by conn ' , IS_USED_LOCK ('job' ))) AS status ;→ -- Free
⚠ Anti-Pattern — KILLing the lock holder without investigation
Seeing IS_USED_LOCK() return a connection ID and immediately KILL-ing it can interrupt important operations.
✓ Instead: Use SHOW PROCESSLIST or query INFORMATION_SCHEMA.PROCESSLIST to understand what the holder is doing before taking action.
◆ MariaDB Note
Returns NULL when the lock is not held by any session.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses pg_locks view to see advisory lock holders.
RELEASE_ALL_LOCKS Available since MariaDB 10.0.2. → INT Releases all named advisory locks held by the current session at once. Returns the number of locks released.
Examples Released 3 locks held by this session
sql copy
SELECT RELEASE_ALL_LOCKS ();→ -- 3
Acquire two then release all
sql copy
SELECT GET_LOCK ('a' ,1 ); SELECT GET_LOCK ('b' ,1 ); SELECT RELEASE_ALL_LOCKS ();→ -- 1 | 1 | 2
No locks held returns 0
sql copy
SELECT RELEASE_ALL_LOCKS ();→ -- 0
Silent release
sql copy
DO RELEASE_ALL_LOCKS ();→ -- (no result set)
Named result column
sql copy
SELECT RELEASE_ALL_LOCKS () AS locks_freed ;→ -- 1
⚠ Anti-Pattern — Relying on session end instead of RELEASE_ALL_LOCKS()
Locks are released when a session closes, but a long-lived connection pool keeps sessions open. This can starve other sessions of advisory locks.
✓ Instead: Call RELEASE_ALL_LOCKS() explicitly in cleanup or FINALLY-equivalent error handler code.
◆ MariaDB Note
Returns count of released locks. Particularly important in MariaDB since multiple named locks per session are the norm.
⇄ vs MySQL: Available in MySQL 5.7.5+. MariaDB has supported multiple locks per session longer.
⇄ vs PostgreSQL: PostgreSQL uses pg_advisory_unlock_all().
MASTER_GTID_WAIT Available since MariaDB 10.0.9. → INT Waits until the replica has applied all transactions up to the given GTID position, or until the timeout expires. Returns 0 on success, -1 on timeout, 1 on error.
Signatures MASTER_GTID_WAIT(gtid_pos)
MASTER_GTID_WAIT(gtid_pos, timeout)
Parameters Parameter Type Description gtid_pos VARCHAR The GTID position string to wait for (e.g., '0-1-100'). timeout DECIMAL Maximum seconds to wait. Omit or use -1 for indefinite wait.
Examples Wait until replica reaches GTID
sql copy
SELECT MASTER_GTID_WAIT ('0-1-150' );→ -- 0
Timeout after 5 seconds
sql copy
SELECT MASTER_GTID_WAIT ('0-1-150' , 5 );→ -- -1
Non-blocking check
sql copy
SELECT MASTER_GTID_WAIT ('0-1-150' , 0 );→ -- 0 or -1
Read-your-own-writes pattern
sql copy
SET @gtid = (SELECT @@last_gtid ); /* do something on replica */ SELECT MASTER_GTID_WAIT (@gtid , 30 );→ -- 0
Status message
sql copy
SELECT IF (MASTER_GTID_WAIT ('0-1-200' , 10 ) = 0 , 'Synced' , 'Timeout' ) AS replication_status ;→ -- Synced
⚠ Anti-Pattern — Using MASTER_GTID_WAIT with an indefinite timeout in production
Omitting the timeout or passing -1 can block an application thread indefinitely if replication lags.
✓ Instead: Always specify a reasonable timeout and handle the -1 (timeout) return value with a fallback or retry.
◆ MariaDB Note
MariaDB GTID format is 'domain_id-server_id-sequence_no', different from MySQL's UUID-based GTIDs.
⇄ vs MySQL: MySQL uses WAIT_FOR_EXECUTED_GTID_SET() with a different GTID format.
⇄ vs PostgreSQL: PostgreSQL uses pg_wal_replay_pause() / pg_wal_replay_resume() and pg_last_wal_replay_lsn() for similar patterns.
SLEEP → INT Pauses execution for the specified number of seconds (fractional seconds supported). Returns 0 on normal completion, 1 if interrupted.
Parameters Parameter Type Description seconds DECIMAL Duration to sleep in seconds. Fractional values (e.g., 0.5) are accepted.
Examples Sleep 1 second
sql copy
SELECT SLEEP (1 );→ -- 0
Sleep 250 milliseconds
sql copy
SELECT SLEEP (0.25 );→ -- 0
Returns 1 if interrupted by KILL
sql copy
SELECT SLEEP (60 );→ -- 1 (if killed)
Use with BENCHMARK
sql copy
SELECT BENCHMARK (1 , SLEEP (2 ));→ -- 0 (after 2 sec)
Zero-sleep status check
sql copy
SELECT IF (SLEEP (0 ) = 0 , 'OK' , 'Interrupted' ) AS status ;→ -- OK
⚠ Anti-Pattern — Using SLEEP() in production queries for throttling
SLEEP() holds a connection and any locks for the entire duration. Using it to throttle query rates blocks connection pool slots.
✓ Instead: Handle throttling in application code, outside the database connection context.
◆ MariaDB Note
Returns 1 when the sleep is interrupted via KILL QUERY.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses pg_sleep(seconds).
UUID → VARCHAR(36) Generates a universally unique identifier (UUID) conforming to RFC 4122 version 1, returned as a 36-character string with hyphens.
Examples Generate UUID v1
sql copy
SELECT UUID ();→ -- '6ccd780c-baba-1026-9564-5b8c656024db'
UUID without hyphens
sql copy
SELECT REPLACE (UUID (), '-' , '' ) AS uuid_hex ;→ -- '6ccd780cbaba102695645b8c656024db'
Use UUID as row ID
sql copy
INSERT INTO events (id , name ) VALUES (UUID (), 'click' );→ -- 1 row affected
Two calls always differ
sql copy
SELECT UUID () = UUID ();→ -- 0
Compact binary storage
sql copy
SELECT UNHEX (REPLACE (UUID (),'-' ,'' )) AS uuid_binary ;→ -- (16 bytes)
⚠ Anti-Pattern — Using VARCHAR(36) UUID as a clustered primary key
Random UUID values inserted as the clustered index key (InnoDB PRIMARY KEY) cause random page splits and severe insert fragmentation.
✓ Instead: Use UUID_SHORT() for monotonic 64-bit IDs, or store UUIDs in BINARY(16) and keep an AUTO_INCREMENT PK for clustering.
◆ MariaDB Note
Returns a UUID v1 (time-based). The MAC address portion may be random on VMs.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses gen_random_uuid() (v4) or uuid_generate_v1() via extension.
UUID_SHORT → BIGINT UNSIGNED Returns a short universally unique 64-bit integer that is monotonically increasing per server. Combines server_id, startup time, and a per-session sequence counter.
Examples 64-bit unique integer
sql copy
SELECT UUID_SHORT ();→ -- 92395783831158784
Monotonically increasing
sql copy
SELECT UUID_SHORT () < UUID_SHORT ();→ -- 1
Use as primary key
sql copy
INSERT INTO records (id , data ) VALUES (UUID_SHORT (), 'hello' );→ -- 1 row affected
Capture for reuse
sql copy
SELECT UUID_SHORT () INTO @id ; SELECT @id ;→ -- 92395783831158784
Pair with timestamp
sql copy
SELECT UUID_SHORT () AS id , NOW () AS created ;→ -- (id | timestamp)
⚠ Anti-Pattern — Using UUID_SHORT() with duplicate server_id values
UUID_SHORT() incorporates @@server_id. If multiple servers have the same server_id (misconfigured replication), UUID_SHORT() can produce collisions.
✓ Instead: Ensure every server in the topology has a unique @@server_id before using UUID_SHORT() as a distributed unique key.
◆ MariaDB Note
The value encodes: (server_id << 56) + (server_startup_time_sec << 24) + per-connection auto-increment.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses sequences or gen_random_uuid(); no direct monotonic 64-bit UUID function.
SYS_GUID Available since MariaDB 10.3 Oracle compatibility mode. → VARCHAR(32) Oracle compatibility function that generates a globally unique identifier. Returns a 32-character hexadecimal string (UUID without hyphens). Only available when the SQL_MODE includes 'ORACLE' or when running MariaDB's Oracle compatibility mode.
Examples UUID in Oracle format
sql copy
SET SQL_MODE = 'ORACLE' ; SELECT SYS_GUID ();→ -- '6CCD780CBABA102695645B8C656024DB'
Always 32 hex characters
sql copy
SET SQL_MODE = 'ORACLE' ; SELECT LENGTH (SYS_GUID ());→ -- 32
Use as row identifier
sql copy
SET SQL_MODE = 'ORACLE' ; INSERT INTO t (id ) VALUES (SYS_GUID ());→ -- 1 row affected
Each call produces unique value
sql copy
SET SQL_MODE = 'ORACLE' ; SELECT SYS_GUID () = SYS_GUID ();→ -- 0
Standard SQL equivalent
sql copy
SELECT REPLACE (UUID (), '-' , '' ) AS same_as_sys_guid ;→ -- '6ccd780cbaba102695645b8c656024db'
⚠ Anti-Pattern — Using SYS_GUID() without Oracle SQL mode enabled
SYS_GUID() is only available in Oracle compatibility mode (sql_mode=ORACLE). Calling it in standard mode raises an error.
✓ Instead: Use UUID() or REPLACE(UUID(), '-', '') in standard MariaDB code.
◆ MariaDB Note
Only available in Oracle SQL mode (sql_mode contains 'ORACLE'). Returns uppercase hex without hyphens.
⇄ vs MySQL: MySQL does not have SYS_GUID(). This is a MariaDB Oracle compatibility extension.
⇄ vs PostgreSQL: PostgreSQL uses gen_random_uuid() which returns UUID v4.