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.
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
MariaDB 5.5+→ VARCHAR
Returns the MariaDB server version string, always including the '-MariaDB' suffix.
Signature
VERSION()
Examples
Get server version
sql
SELECTVERSION();
→-- 10.11.4-MariaDB
System variable alternative
sql
SELECT @@version;
→-- 10.11.4-MariaDB
Confirm running MariaDB
sql
SELECTVERSION() LIKE'%MariaDB%';
→-- 1
Extract major version
sql
SELECTSUBSTRING_INDEX(VERSION(), '.', 1) ASmajor;
→-- 10
Store in variable
sql
SELECTVERSION() 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.
VERSION() always contains '-MariaDB' in MariaDB. Use VERSION() LIKE '%MariaDB%' in compatibility checks or stored procedures that must behave differently on MySQL vs MariaDB.
⚠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.
DATABASE() returns NULL outside of any USE statement context, such as in event scheduler procedures or connections where no schema is set. Guard against this with COALESCE(DATABASE(), 'none').
⚠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.
SCHEMA() is a non-standard alias for DATABASE(). Most developers recognize DATABASE() immediately; SCHEMA() can be confused with information_schema. Use DATABASE() in new code for wider familiarity.
example
SELECTDATABASE() ASdb, SCHEMA() ASsch;
→db: 'myapp', sch: 'myapp'
◆MariaDB Note
Exact synonym for DATABASE().
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses current_schema() or current_database().
Returns the current MariaDB user and host as 'user@host', representing the connection's authentication credentials.
Signature
USER()
Examples
Current user and host
sql
SELECTUSER();
→-- admin@localhost
Extract just the username
sql
SELECTSUBSTRING_INDEX(USER(), '@', 1) ASusername;
→-- admin
Extract just the host
sql
SELECTSUBSTRING_INDEX(USER(), '@', -1) AShost;
→-- localhost
Compare to current_user
sql
SELECTUSER() =CURRENT_USER();
→-- 1 (usually)
DUAL table form
sql
SELECTUSER() FROMDUAL;
→-- 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.
USER() returns 'username@hostname' where hostname is the client's connecting address. This is more specific than CURRENT_USER() which returns the matched auth pattern. Use USER() in audit triggers to capture the actual connecting host.
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
SELECTCURRENT_USER();
→-- admin@%
Without parentheses (standard SQL)
sql
SELECTCURRENT_USER;
→-- admin@%
May differ with wildcards
sql
SELECTUSER(), CURRENT_USER();
→-- admin@localhost | admin@%
Show own grants
sql
SHOWGRANTSFORCURRENT_USER();
→-- GRANT ... TO 'admin'@'%'
Store in variable
sql
SELECTCURRENT_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.
CURRENT_USER() returns the matched entry from the mysql.user table, such as 'app@%'. This is useful for permission checks because it reflects the privilege row being used, not the specific connecting host.
⚠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.
SESSION_USER() and USER() return identical values. SESSION_USER() exists for SQL standard compatibility. In MariaDB code, USER() is more commonly seen and immediately recognizable.
⚠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.
In MariaDB, SYSTEM_USER() is simply another alias for USER(). This differs from SQL Server where SYSTEM_USER refers to the OS-level login. Do not assume OS-level semantics when reading MariaDB code.
⚠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.
CONNECTION_ID() is stable for the lifetime of a connection and useful for advisory locking patterns (GET_LOCK), for labeling rows in audit tables, and for matching entries in INFORMATION_SCHEMA.PROCESSLIST.
⚠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.
LAST_INSERT_ID() returns the AUTO_INCREMENT value generated by the most recent INSERT on the current connection. Other connections' inserts do not affect it, making it safe for concurrent workloads without locking.
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.
ROW_COUNT() returns -1 after a SELECT statement. It only reflects DML operations.
✓ Instead: Use FOUND_ROWS() or COUNT(*) to count SELECT results.
ROW_COUNT() is reset by every subsequent statement, including a SELECT. Call it in the very next statement after the INSERT/UPDATE/DELETE to capture the correct value, or assign it to a variable immediately.
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.
⚠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.
FOUND_ROWS() only works when the preceding SELECT included SQL_CALC_FOUND_ROWS. On MariaDB 10.1+ with optimizations, SQL_CALC_FOUND_ROWS can add overhead. For new pagination code, a separate COUNT(*) query with the same WHERE clause is often cleaner and more index-friendly.
⚠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.
BENCHMARK(n, expr) executes expr n times and returns 0 (the duration is shown in the client's timing). It is useful for comparing two alternative expressions (e.g., SHA1 vs SHA2, REGEXP vs LIKE) without the overhead of table scans.
example
SELECTBENCHMARK(1000000, SHA2('test', 256));
→0 (check client elapsed time for comparison)
◆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.
Returns the character set of a string argument. Reflects the character set encoding of the given value.
Signature
CHARSET(str)
Parameters
Parameter
Type
Description
str
VARCHAR/any
The string value whose character set is to be returned.
Examples
Default client charset
sql
SELECTCHARSET('hello');
→-- utf8mb4
After CONVERT
sql
SELECTCHARSET(CONVERT('hello'USINGlatin1));
→-- latin1
System function result charset
sql
SELECTCHARSET(USER());
→-- utf8mb3
Check column charset
sql
SELECTcol, CHARSET(col) FROMtLIMIT1;
→-- (col value) | utf8mb4
Charset introducer
sql
SELECTCHARSET(_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.
CHARSET(expr) reveals the character set of any string expression or column. When a JOIN or comparison produces unexpected results, checking CHARSET on both sides quickly identifies a charset mismatch.
Returns the collation coercibility value of a string argument. The coercibility value determines which collation wins when two strings of different collations are compared.
Signature
COERCIBILITY(str)
Parameters
Parameter
Type
Description
str
VARCHAR/any
The string expression whose coercibility is checked.
Examples
Literal string = coercibility 4
sql
SELECTCOERCIBILITY('hello');
→-- 4
System function = coercibility 3
sql
SELECTCOERCIBILITY(USER());
→-- 3
Column = coercibility 2
sql
SELECTCOERCIBILITY(col) FROMtLIMIT1;
→-- 2
Explicit COLLATE = coercibility 0
sql
SELECTCOERCIBILITY('x'COLLATEutf8mb4_bin);
→-- 0
NULL = coercibility 6 (ignorable)
sql
SELECTCOERCIBILITY(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.
When two operands in a comparison have different collations, the one with the lower coercibility value 'wins'. Literals have coercibility 4; columns have 2; explicit COLLATE clauses have 0. Understanding this prevents 'Illegal mix of collations' errors.
Returns the collation name of the given string argument.
Signature
COLLATION(str)
Parameters
Parameter
Type
Description
str
VARCHAR/any
The string expression whose collation is to be returned.
Examples
Default collation for literal
sql
SELECTCOLLATION('hello');
→-- utf8mb4_general_ci
Collation of a table column
sql
SELECTCOLLATION(col) FROMtLIMIT1;
→-- utf8mb4_unicode_ci
After CONVERT
sql
SELECTCOLLATION(CONVERT('hi'USINGutf8mb4));
→-- utf8mb4_general_ci
Explicit collation
sql
SELECTCOLLATION('x'COLLATEutf8mb4_bin);
→-- utf8mb4_bin
System function collation
sql
SELECTCOLLATION(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.
COLLATION(expr) shows the collation that will be used when the expression participates in a comparison or sort. In queries mixing columns from tables with different default collations, checking COLLATION() on both sides reveals implicit coercions.
example
SELECTCOLLATION(name) FROMusersLIMIT1;
→utf8mb4_unicode_ci
◆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.
⚠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 10.0.5+ supports role-based access control. CURRENT_ROLE() returns the currently active role(s) for the session. Use it in security audit queries or stored procedures that must behave differently based on the caller's role.
example
SELECTCURRENT_ROLE();
→'analyst' (or 'NONE' if no role is set)
◆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).
⚠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().
DEFAULT(col) returns the default value defined for the column in the table's CREATE TABLE statement. Use it in UPDATE statements to restore a column to its original default without hardcoding the value in application code.
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.
Signature
GET_LOCK(str, timeout)
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).
SELECTGET_LOCK('task', 30) INTO @got; IF @got=1THEN/* do work */ENDIF;
→-- 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().
GET_LOCK creates a named advisory lock scoped to the connection. The name can be any string up to 64 characters. Use consistent naming conventions (e.g., 'app:resource:id') to avoid accidental conflicts between different lock namespaces.
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().
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.
Signature
RELEASE_LOCK(str)
Parameters
Parameter
Type
Description
str
VARCHAR
The name of the advisory lock to release.
Examples
Successfully released
sql
SELECTRELEASE_LOCK('my_task');
→-- 1
Lock does not exist
sql
SELECTRELEASE_LOCK('nonexistent_lock');
→-- NULL
Not held by this thread
sql
SELECTRELEASE_LOCK('other_sessions_lock');
→-- 0
Acquire then release pattern
sql
SELECTGET_LOCK('job', 10); /* work */SELECTRELEASE_LOCK('job');
→-- 1 | 1
Release multiple locks
sql
SELECTRELEASE_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.
Advisory locks are automatically released when the connection closes, but in long-lived connection pools a lock may be held until the connection is recycled. Always release locks explicitly in a DECLARE ... HANDLER block or application try/finally.
⚠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).
IS_FREE_LOCK returns 1 if the lock is not held by any connection, 0 if it is, and NULL on error. Unlike GET_LOCK with timeout=0, IS_FREE_LOCK does not attempt to acquire the lock — it only checks availability.
example
SELECTIS_FREE_LOCK('cron:daily_report') ASfree;
→free: 1 (available) or 0 (currently held)
◆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.
SELECTIF(IS_USED_LOCK('job') ISNULL, 'Free', CONCAT('Held by conn ', IS_USED_LOCK('job'))) ASstatus;
→-- 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.
IS_USED_LOCK returns the connection_id of the session holding the named lock, or NULL if the lock is free. Cross-reference with INFORMATION_SCHEMA.PROCESSLIST to identify which query is holding a long-running advisory lock.
⚠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.
RELEASE_ALL_LOCKS() releases every advisory lock held by the current session in one call. Include it in connection reset procedures or in AFTER SIGNAL handlers to guarantee no orphaned locks remain.
example
SELECTRELEASE_ALL_LOCKS() ASlocks_released;
→locks_released: 3 (number of locks released)
◆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().
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
SELECTMASTER_GTID_WAIT('0-1-150');
→-- 0
Timeout after 5 seconds
sql
SELECTMASTER_GTID_WAIT('0-1-150', 5);
→-- -1
Non-blocking check
sql
SELECTMASTER_GTID_WAIT('0-1-150', 0);
→-- 0 or -1
Read-your-own-writes pattern
sql
SET @gtid= (SELECT @@last_gtid); /* do something on replica */SELECTMASTER_GTID_WAIT(@gtid, 30);
⚠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.
After a write on the primary, capture @@last_gtid before the response is sent to the client. Pass this value to MASTER_GTID_WAIT() on the replica connection to ensure read-after-write consistency without polling.
example
SELECTMASTER_GTID_WAIT('0-1-452', 5) ASsynced;
→synced: 0 (success) or -1 (timeout after 5 seconds)
◆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.
⚠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.
SLEEP() is valuable in test scripts to simulate slow queries, lock contention scenarios, or replication delay. In production it holds a connection and its locks for the full duration — never leave SLEEP() calls in production code paths.
example
SELECTSLEEP(0.1); -- 100ms pause for test pacing
→0
◆MariaDB Note
Returns 1 when the sleep is interrupted via KILL QUERY.
⇄ vs MySQL: Identical in MySQL.
⇄ vs PostgreSQL: PostgreSQL uses pg_sleep(seconds).
⚠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.
UUID() returns a 36-character string with hyphens. Storing it as VARCHAR(36) wastes space and makes index comparisons slower. Use UNHEX(REPLACE(UUID(),'-','')) to get a 16-byte binary suitable for a BINARY(16) primary key column.
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.
⚠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.
UUID_SHORT() returns a monotonically increasing BIGINT that avoids the index fragmentation of random UUIDs while still being unique across servers with distinct server_id values. It inserts in order, keeping B-tree indexes efficient.
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.
⚠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.
SYS_GUID() returns the same UUID as UUID() but without hyphens, matching Oracle's SYS_GUID() return format. Use it only when porting Oracle PL/SQL that relies on the 32-character no-hyphen format.
example
SELECTSYS_GUID();
→'6CCD780CBABA102695645B8C656024DB' (32 chars, no hyphens)
◆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.