MySQL Variables
Master MySQL's three flavors of variables — local variables (DECLARE in BEGIN...END), user variables (@x, session-scoped), and system variables (@@x, server configuration). Covers SET vs SELECT INTO assignment, the := operator, SHOW VARIABLES, SET PERSIST in MySQL 8.0, and best practices for choosing the right kind for each scenario.
MySQL has three different kinds of variables, each with its own scope, syntax, and lifetime. They're easy to confuse — and mixing them up causes some of the most common stored-procedure bugs.
| Kind | Prefix | Scope | Lifetime |
|---|---|---|---|
| Local variable | None | Inside the BEGIN ... END block where it's declared | Lives until the block ends |
| User variable | @ | The current connection (session) | Lives until the connection closes |
| System variable | @@ | Server-wide (GLOBAL) or per-session (SESSION) | Persists with the server (GLOBAL) or session (SESSION) |
Local variables are declared inside BEGIN ... END blocks (typically inside stored procedures, functions, or triggers). They have:
- No
@prefix — just the name. - A required data type — strongly typed, you must declare it.
- Block scope — visible only inside the
BEGIN ... ENDthey were declared in. - An optional default via
DEFAULT; otherwise initialized to NULL.
- All
DECLAREs come first in aBEGIN ... ENDblock — before any other statement. The order is variables → cursors → handlers. - One DECLARE statement = one data type. You can declare multiple variables in one statement only if they share a type:
DECLARE a, b, c INT DEFAULT 0;works;DECLARE a INT, b VARCHAR(10);does not.
Declare a few salaries, sum them, return the result. The original tutorial had several typos in this procedure — missing semicolons, missing space between DECLARE and Lex, inconsistent variable casing — corrected below:
DROP PROCEDURE IF EXISTS salaries;
DELIMITER $$
CREATE PROCEDURE salaries()
BEGIN
DECLARE steven INT;
DECLARE neena INT DEFAULT 18000;
DECLARE lex INT;
DECLARE bruce INT;
DECLARE total INT;
SET steven = 25000;
SET lex = 20000;
SET bruce = 10000;
SET total = steven + neena + lex + bruce;
SELECT total, steven, neena, lex, bruce;
END$$
DELIMITER ;
CALL salaries();
SET var = expression;— assign a single valueSELECT col INTO var FROM table WHERE ...;— pull from a query (must return exactly one row)
User variables — the @ kind — are session-scoped. They live for the duration of your connection and are visible everywhere in that session: from the CLI, from procedures called by your session, from any query you run.
Unlike local variables, they:
- Don't need declaration — first assignment creates them.
- Are loosely typed — type is inferred from the value.
- Persist across statements — set in one query, read in the next.
- Are case-insensitive —
@nameand@NAMEare the same variable.
SET @name = 'Gowtham';
SELECT @name;
SELECT @var := value assigns and returns the value in one shot. Useful when you want to capture a query result in a variable while also displaying it:
SELECT @max_salary := MAX(salary) FROM employees;
-- Now use it
SELECT * FROM employees WHERE salary = @max_salary;
:= in SELECT, = in SET. Inside SET, both = and := work for assignment. Inside SELECT, only := assigns — plain = is comparison. The two-character form is unambiguous and works everywhere; some teams use it always for consistency.CALL proc(@x, @y), those @ variables hold the OUT/INOUT results — they're how the procedure communicates back to your session.System variables — the @@ kind — are MySQL's configuration knobs. They control server behavior: connection limits, character sets, buffer sizes, transaction isolation, autocommit mode, and hundreds more.
Two scopes:
| Scope | Affects | Persists? |
|---|---|---|
GLOBAL (@@GLOBAL.x) | Server-wide for all sessions | Until server restart (some can be made permanent via SET PERSIST) |
SESSION (@@SESSION.x or @@x) | Just your current connection | Until you disconnect |
The SHOW VARIABLES command lists system variables. Filter with LIKE to find a specific one:
SHOW VARIABLES LIKE '%table%';
Use SELECT @@var_name to read a single system variable's current value:
SELECT @@version, @@autocommit, @@max_connections;
Many system variables are dynamic — you can change them at runtime with SET:
-- Just for this session
SET SESSION sql_mode = 'STRICT_ALL_TABLES';
-- Server-wide (requires SUPER privilege)
SET GLOBAL max_connections = 200;
-- Persistent across server restarts (MySQL 8.0+)
SET PERSIST max_connections = 200;
@@version, @@datadir, @@hostname reflect server state that you can't change at runtime — attempting to SET them gives an error. Check the docs for which variables are dynamic (changeable) vs static (read-only).| You want to… | Use this |
|---|---|
| Hold a temporary value inside a procedure | Local variable: DECLARE x INT; |
| Pass a value between statements in your session | User variable: SET @x = ...; |
| Receive an OUT or INOUT parameter from a procedure | User variable: CALL proc(..., @result); |
| Read MySQL server configuration | System variable: SELECT @@var_name; |
| Tweak server behavior at runtime | System variable: SET SESSION/GLOBAL var = ...; |
- Use local variables inside procedures by default. They're typed, scoped, and predictable.
- Watch for variable / column name shadowing. If a local variable shares its name with a table column, MySQL uses the variable in expressions but the column in WHERE clauses — easy bug to introduce. Prefix locals (
v_total) or pick distinct names. - Reach for user variables when you need session-scoped state — running totals across queries, OUT parameter receivers, parameterized scripts.
- Don't overuse user variables. They're not type-safe and they leak across scope boundaries; relying on them for procedural state is fragile.
- Treat system variables as configuration. Read them freely, but be deliberate about
SET GLOBAL/SET PERSIST— those changes affect the whole server. - Initialize local variables explicitly.
DECLARE total INT DEFAULT 0;is clearer thanDECLARE total INT;(which starts as NULL — andNULL + anythingis still NULL).
- MySQL has three kinds of variables: local (no prefix, declared in
BEGIN ... END), user (@prefix, session-scoped), system (@@prefix, server configuration). - Local variables need
DECLARE var [, var ...] datatype [DEFAULT value];at the top of their block. AllDECLAREs come before any other statement. - User variables are loosely typed, case-insensitive, persist for the connection, and don't need declaration. Set with
SET @x = ...;orSELECT @x := ...;. - System variables are MySQL's configuration. Read with
SELECT @@varorSHOW VARIABLES LIKE '...';; change withSET SESSION,SET GLOBAL, orSET PERSIST(8.0+). - Use the right tool: locals for procedure-internal state, user variables for cross-statement values and OUT-parameter receivers, system variables for MySQL configuration.