MariaDB Enterprise Server provides DDL (Data Definition Language) syntax to create, alter, or drop constraints.
In the context of ISO 9075-2:2016, this page uses "DDL (Data Definition Language)" to refer to SQL statements in the standard's "SQL-schema statements" group.
When creating a table, you can define a column with a NOT NULL constraint to prevent null values. This constraint ensures data integrity by guaranteeing that a column must always contain a value. If an attempt is made to insert or update a row with a null value in a NOT NULL column, the operation will be rejected, thus maintaining the integrity of the database.
MariaDB Server supports NOT NULL constraints to ensure that a column's value is not set to NULL:
When a column is declared with a NOT NULL constraint, Enterprise Server rejects operations that would write a NULL value to the column
With MariaDB Server, the statement can be used to create a new table with a NOT NULL constraint on one or more columns:
With MariaDB Server, the statement can be used to add the NOT NULL constraint to a column using the MODIFY COLUMN clause:
With MariaDB Server, the statement can be used to remove the NOT NULL constraint from a column using the MODIFY COLUMN clause:
CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY (invoice_id)
);ALTER TABLE hq_sales.invoices
MODIFY COLUMN customer_id INT NOT NULL;
ALTER TABLE .. MODIFY COLUMN .. NULLALTER TABLE hq_sales.invoices
MODIFY COLUMN customer_id INT NULL;Understand MariaDB Server's architectural constraints. This section details limitations & design considerations, helping you optimize your database deployments for maximum efficiency and scalability.
The unique_checks system variable in MariaDB Server can be utilized to disable unique checks, which might be useful in specific scenarios where enforcing unique constraints temporarily is not required. This can enhance performance during bulk inserts, for instance.
MariaDB Server supports UNIQUE constraints to ensure that a column's value is unique within a table:
MariaDB Server uses unique indexes to speed up query execution and enforce unique constraints
MariaDB Server supports single column and composite (multi-column) unique indexes
MariaDB Community Server can have up to 64 total indexes for a given table.
MariaDB Server can have up to 128 total indexes for a given table.
InnoDB stores unique indexes in the same tablespace file as the clustered index and data.
Unique indexes are B+ trees, which are very efficient for searching for exact values, performing range scans, and checking uniqueness.
If no primary key is defined for a table, then InnoDB will use the table's first NOT NULL unique index as the table's primary key.
If no primary key or NOT NULL unique index is defined for a table, then InnoDB will automatically create a primary key called GEN_CLUST_INDEX, using an internal 48-bit DB_ROW_ID column as the key. Replication with such tables can be very slow, especially when is MIXED or ROW.
MariaDB Server provides the , which can be used to disable unique checks.
When unique checks are disabled, the InnoDB change buffer is used for inserts into unique indexes, and duplicate values will not be detected.
Disabling unique checks can speed up bulk data loads, but it is dangerous to do so.
Let's create an InnoDB table with a single column unique index after confirming that the default storage engine is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the table using the statement:
Create the table using the statement and specify the unique index with the UNIQUE INDEX() clause:
For a single column unique index, the unique index can also be specified with the UNIQUE column option:
Let's create an InnoDB table with a composite (multi-column) unique index after confirming that the default storage engine is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the table using the statement:
Create the table using the statement and specify the unique index with the UNIQUE INDEX() clause:
Let's create an InnoDB table with a unique index on a single column prefix after confirming that the default storage engine is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the table using the statement:
Create the table using the statement and specify the unique index with the UNIQUE INDEX() clause:
The unique index is specified with the product_description(1000) prefix, so only the first 1000 characters of the product_description column for each row will be indexed and checked for uniqueness.
Let's create an InnoDB table without a unique index, and then add a unique index to it:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the table using the statement:
Create the table without a primary key using the statement:
Alter the table using the statement and specify the new unique index with the ADD UNIQUE INDEX() clause:
Let's drop the unique index from the table created in the section:
Obtain the name of the index by joining the , , and tables:
Alter the table using the statement and specify the DROP INDEX clause:
Let's rebuild the unique index in the table created in the section:
Obtain the name of the index by joining the , , and tables:
Alter the table using the statement and specify the DROP INDEX clause:
Alter the table using the statement and specify the unique index with the ADD UNIQUE INDEX() clause:
Using an AUTO_INCREMENT column as the primary key in MariaDB is beneficial for ensuring unique row identification and efficient data retrieval. This approach automatically generates a unique integer for each new row, simplifying primary key management. It is especially useful in tables where data insertion occurs frequently, as it facilitates quick indexing and minimizes storage overhead due to its numeric nature. This practice helps maintain optimal performance in database operations, particularly when combined with clustered indexing in InnoDB.
MariaDB Server supports PRIMARY KEY constraints to uniquely identify rows:
There can only be a single primary key for a given table.
InnoDB uses the primary key as a clustered index, which means that InnoDB stores table data in the order determined by the primary key.
Primary key indexes are B+ trees, which are very efficient for searching for exact values, performing range scans, and checking uniqueness.
If no primary key is defined for a table, then InnoDB will use the table's first NOT NULL unique index as the table's primary key.
If no primary key or NOT NULL unique index is defined for a table, then InnoDB will automatically create a primary key called GEN_CLUST_INDEX, using an internal 48-bit DB_ROW_ID column as the key. Replication with such tables can be very slow, especially when is MIXED or ROW!
For best performance, users should always create primary keys for their tables, and primary keys should be short, because the primary key columns are duplicated in every secondary index record.
If your table does not have a column or a set of columns that could act as a natural primary key, then you can define a single AUTO_INCREMENT column, which can serve as the table's primary key. See InnoDB AUTO_INCREMENT Columns for more details.
If your table does not have a column or a set of columns that could act as a natural primary key, then you can use a sequence to generate an integer value to use as the table's primary key. Sequences were first added in MariaDB Server 10.3 and MariaDB Community Server 10.3. See InnoDB Sequences for more details.
Let's create an InnoDB table with a single column primary key after confirming that the default storage engine is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the default_storage_engine system variable using the SHOW SESSION VARIABLES statement:
If the database does not exist, then create the database for the table using the CREATE DATABASE statement:
Create the table using the CREATE TABLE statement and specify the primary key with the PRIMARY KEY() clause:
For a single column primary key, the primary key can also be specified with the PRIMARY KEY column option:
Let's create an InnoDB table with a composite (multi-column) primary key after confirming that the default storage engine is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the default_storage_engine system variable using the SHOW SESSION VARIABLES statement:
If the database does not exist, then create the database for the table using the CREATE DATABASE statement:
Create the table using the CREATE TABLE statement and specify the primary key with the PRIMARY KEY() clause:
Let's create an InnoDB table without a primary key, and then add a primary key to it:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the default_storage_engine system variable using the SHOW SESSION VARIABLES statement:
If the database does not exist, then create the database for the table using the CREATE DATABASE statement:
Create the table without a primary key using the CREATE TABLE statement:
Alter the table using the ALTER TABLE statement and specify the new primary key with the ADD PRIMARY KEY() clause:
Let's drop the primary key from the table created in the create an InnoDB table without a primary key section:
Alter the table using the ALTER TABLE statement and specify the DROP PRIMARY KEY clause:
Let's change the primary key from the table created in the create an InnoDB table without a primary key section:
Alter the table using the ALTER TABLE statement and specify the DROP PRIMARY KEY clause to drop the old primary key, and specify the new primary key with the ADD PRIMARY KEY() clause:
For best performance, every InnoDB table should have a primary key. It is possible to find tables without a primary key using a basic SELECT statement.
Let's create an InnoDB table without a primary key, and then use a SELECT statement to confirm that it does not have one:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the default_storage_engine system variable using the SHOW SESSION VARIABLES statement:
If the database does not exist, then create the database for the table using the CREATE DATABASE statement:
Create the table without a primary key using the CREATE TABLE statement:
Query the information_schema.TABLES and information_schema.KEY_COLUMN_USAGE tables to find InnoDB tables that do not have a primary key:
To add a primary key, alter the table using the ALTER TABLE statement, and specify the primary key with the ADD PRIMARY KEY() clause:
A primary key uniquely identifies every row. Therefore, if a second row is inserted with an identical value, it will fail.
Let's try to insert two identical primary key values into the table created in the Creating an InnoDB Table with a Single Column Primary Key section:
Insert a row with the INSERT statement:
Insert a second row that has the same primary key value with the INSERT statement:
This will fail with the ER_DUP_ENTRY error code:
Fix the problem by inserting the row with a unique primary key value:
To easily generate unique values for a primary key, consider using one of the following options:
This page is: Copyright © 2025 MariaDB. All rights reserved.
This page is: Copyright © 2025 MariaDB. All rights reserved.
This page is: Copyright © 2025 MariaDB. All rights reserved.
This page is: Copyright © 2025 MariaDB. All rights reserved.
$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY(invoice_id)
);CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD')
);$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY(invoice_id, branch_id)
);$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD')
);ALTER TABLE hq_sales.invoices ADD PRIMARY KEY (invoice_id);ALTER TABLE hq_sales.invoices DROP PRIMARY KEY;ALTER TABLE hq_sales.invoices
DROP PRIMARY KEY,
ADD PRIMARY KEY (invoice_id, branch_id);$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD')
);SELECT t.TABLE_SCHEMA, t.TABLE_NAME
FROM information_schema.TABLES AS t
LEFT JOIN information_schema.KEY_COLUMN_USAGE AS c
ON t.TABLE_SCHEMA = c.CONSTRAINT_SCHEMA
AND t.TABLE_NAME = c.TABLE_NAME
AND c.CONSTRAINT_NAME = 'PRIMARY'
WHERE t.TABLE_SCHEMA != 'mysql'
AND t.ENGINE = 'InnoDB'
AND c.CONSTRAINT_NAME IS NULL;+--------------+------------+
| TABLE_SCHEMA | TABLE_NAME |
+--------------+------------+
| hq_sales | invoices |
+--------------+------------+ALTER TABLE hq_sales.invoices ADD PRIMARY KEY (invoice_id);INSERT INTO hq_sales.invoices
(invoice_id, branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 1, 1, '2020-05-10 12:35:10', 1087.23, 'CREDIT_CARD');INSERT INTO hq_sales.invoices
(invoice_id, branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 1, 2, '2020-05-10 14:17:32', 1508.57, 'WIRE_TRANSFER');ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'INSERT INTO hq_sales.invoices
(invoice_id, branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(2, 1, 2, '2020-05-10 14:17:32', 1508.57, 'WIRE_TRANSFER');$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.customers (
customer_id BIGINT AUTO_INCREMENT NOT NULL,
customer_name VARCHAR(500),
customer_email VARCHAR(200),
PRIMARY KEY(customer_id),
UNIQUE INDEX(customer_email)
);CREATE TABLE hq_sales.customers (
customer_id BIGINT AUTO_INCREMENT NOT NULL,
customer_name VARCHAR(500),
customer_email VARCHAR(200) UNIQUE,
PRIMARY KEY(customer_id)
);$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY(invoice_id),
UNIQUE INDEX(invoice_date, customer_id, branch_id)
);$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.products (
product_id BIGINT AUTO_INCREMENT NOT NULL,
product_name VARCHAR(500),
product_brand VARCHAR(500),
product_description TEXT,
PRIMARY KEY(product_id),
UNIQUE INDEX(product_description(1000))
);$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.customers (
customer_id BIGINT AUTO_INCREMENT NOT NULL,
customer_name VARCHAR(500),
customer_email VARCHAR(200),
PRIMARY KEY(customer_id)
);ALTER TABLE hq_sales.customers ADD UNIQUE INDEX (customer_email);SELECT isi.NAME AS index_name, isf.NAME AS index_column
FROM information_schema.INNODB_SYS_INDEXES isi
JOIN information_schema.INNODB_SYS_TABLES ist
ON isi.TABLE_ID = ist.TABLE_ID
JOIN information_schema.INNODB_SYS_FIELDS isf
ON isi.INDEX_ID = isf.INDEX_ID
WHERE ist.NAME = 'hq_sales/customers'
ORDER BY isf.INDEX_ID, isf.POS;+----------------+----------------+
| index_name | index_column |
+----------------+----------------+
| PRIMARY | customer_id |
| customer_email | customer_email |
+----------------+----------------+ALTER TABLE hq_sales.customers DROP INDEX customer_email;SELECT isi.NAME AS index_name, isf.NAME AS index_column
FROM information_schema.INNODB_SYS_INDEXES isi
JOIN information_schema.INNODB_SYS_TABLES ist
ON isi.TABLE_ID = ist.TABLE_ID
JOIN information_schema.INNODB_SYS_FIELDS isf
ON isi.INDEX_ID = isf.INDEX_ID
WHERE ist.NAME = 'hq_sales/customers'
ORDER BY isf.INDEX_ID, isf.POS;+----------------+----------------+
| index_name | index_column |
+----------------+----------------+
| PRIMARY | customer_id |
| customer_email | customer_email |
+----------------+----------------+ALTER TABLE hq_sales.customers DROP INDEX customer_email;ALTER TABLE hq_sales.customers ADD UNIQUE INDEX (customer_email);In MariaDB Server, FOREIGN KEY constraints are key elements in defining relationships between InnoDB tables: they ensure referential integrity by maintaining valid associations between rows in parent and child tables. Changes in the parent table can either be restricted or propagated to maintain consistency with child tables.
MariaDB Server supports FOREIGN KEY constraints to define referential constraints between InnoDB tables:
Referential constraints allow the database to automatically ensure that each row in the child table is associated with a valid row in the parent table
If the row in the parent table changes, MariaDB Server can block the change to protect child rows, or propagate the change to the child rows
Foreign keys allow the database to handle certain types of referential constraint checks, so that the application does not have to handle them. As a consequence, application logic can be simplified.
Some example use cases are described below.
Many different applications have account management features. Foreign keys can be used to simplify certain aspects of managing accounts, such as:
If an account is deleted, foreign keys can be used to automatically delete data associated with the account.
If an account is deleted, foreign keys can be used to automatically disassociate its data, so that it is no longer associated with any account.
If an account's user name or user ID is updated, foreign keys can be used to automatically associate its data with the new user name or user ID.
Foreign keys can also be used to simplify certain aspects of managing a store inventory, such as:
If a product is deleted, foreign keys can be used to automatically delete data associated with the product, such as reviews and images.
If a product's name is changed, foreign keys can be used to automatically associate the new name with the product's other data.
If a customer purchases a product, foreign keys can be used to associate the order with the product.
If a customer reviews a product, foreign keys can be used to associate the review with the product.
When an InnoDB table has a foreign key or when it is referenced by a foreign key, InnoDB performs a referential constraint check when certain types of operations try to write to the table. The specific details depend on whether the table is a parent table or a child table.
When an InnoDB table has a foreign key, it is known as a parent table. InnoDB performs referential constraint checks for the following operations on parent tables:
When InnoDB performs a referential constraint check, the outcome depends on several factors. The following table describes the details:
When an InnoDB table is referenced by a foreign key, it is known as a child table. InnoDB performs referential constraint checks for the following operations on child tables:
When InnoDB performs a referential constraint check, the outcome depends on several factors. The following table describes the details:
Let's create InnoDB tables with a foreign key constraint after confirming that the is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the sequence and table using the statement:
Create the parent table using the statement:
Create the child table using the statement:
Insert some rows into the parent table using the statement:
Insert a row into the child table for each row in the parent table using the statement:
Attempt to delete a row from the parent table that has a corresponding row in the child table using the DELETE statement:
This will fail with the error code as explained in the Operating on a Parent Table section:
Attempt to insert a row into the child table for a non-existent row in the parent table using the INSERT statement:
This will fail with the error code as explained in the Operating on a Child Table section:
Let's create InnoDB tables after confirming that the is InnoDB, and then let's add a foreign key constraint between them:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the sequence and table using the statement:
Create the parent table using the statement:
Create the child table using the statement:
Alter the child table to add the foreign key constraint using the statement:
Insert some rows into the parent table using the statement:
Insert a row into the child table for each row in the parent table using the statement:
Attempt to delete a row from the parent table that has a corresponding row in the child table using the statement:
This will fail with the error code as explained in the Operating on a Parent Table section:
Attempt to insert a row into the child table for a non-existent row in the parent table using the statement:
This will fail with the error code as explained in the Operating on a Child Table section:
Let's drop the foreign key constraint from the child table created in the section:
Connect to the server using MariaDB Client:
Obtain the name of the foreign key constraint by querying the table:
Drop the foreign key constraint from the child table using the statement:
When performing bulk data loads, dropping a table, or rebuilding a table, it can improve performance to temporarily disable foreign key constraint checks. Foreign key constraint checks can be temporarily disabled by setting the session value for the foreign_key_checks system variable. If foreign key constraint checks are temporarily disabled, then rows can be inserted that violate the constraint, so users must proceed with caution. This feature is most useful when you are loading a data set that is known to be valid.
Let's temporarily disable foreign key constraint checks, and then perform some tasks with the tables created in the section:
Connect to the server using MariaDB Client:
Temporarily disable foreign key constraint checks by setting the system variable with the statement:
If you want to test how to introduce inconsistencies, then attempt to delete a row from the parent table that has a corresponding row in the child table using the statement:
This operation would usually fail with the error code as explained in the Operating on a Parent Table section, but if foreign key constraint checks are disable, then it will succeed.
If you want to test how to introduce inconsistencies, then also attempt to insert a row into the child table for a non-existent row in the parent table using the statement:
This operation would usually fail with the error code as explained in the section, but if foreign key constraint checks are disable, then it will succeed.
Re-enable foreign key constraint checks by setting the system variable with the statement:
When a foreign key constraint is created without a name, InnoDB implicitly gives it a name in the format:
If foreign key constraints are explicitly created with names in the same format, it is possible for collisions to occur during table renames. In that case, the would contain messages like the following:
A foreign key constraint requires an index on the column. If a foreign key constraint is added to a column without an index, InnoDB will automatically create an index to enforce the foreign key constraint.
When the system variable is disabled, it is possible to drop the index used by a foreign key constraint. When the system variable is re-enabled, InnoDB will have no way to enforce the foreign key constraint, so all operations that could potentially violate the foreign key constraint will fail.
InnoDB finds corresponding rows in the child table
ON UPDATE SET NULL
• Success. • Row in the parent table is updated. • Corresponding rows in the child table are also updated with NULL. If the child table has an update trigger, the trigger will not be executed for the update.
InnoDB does not find any corresponding rows in the child table
NA
• Success. • Row in the parent table is updated
InnoDB finds corresponding rows in the child table
ON DELETE RESTRICT
• Fails with error code
InnoDB finds corresponding rows in the child table
ON DELETE NO ACTION
• Fails with error code
InnoDB finds corresponding rows in the child table
ON DELETE CASCADE
• Success. • Row in the parent table is deleted. • Corresponding rows in the child table are also deleted. If the child table has a delete trigger, the trigger will not be executed for the delete.
InnoDB finds rows in the child table for the row
ON DELETE SET NULL
• Success. • Row in the parent table is deleted. • Corresponding rows in the child table are updated with NULL. If the child table has an update trigger, the trigger will not be executed for the update.
InnoDB does not find any rows in the child table for the row
NA
• Success. • Row in the parent table is deleted
New foreign key value is not present in parent table
Fails with error code
New foreign key value is NULL
Success
Table is referenced by a foreign key
Fails with error code
parent table
A table that has a foreign key.
child table
A table that is referenced by a foreign key.
InnoDB finds corresponding rows in the child table
ON UPDATE RESTRICT
• Fails with ER_ROW_IS_REFERENCED_2 error code
InnoDB finds corresponding rows in the child table
ON UPDATE NO ACTION
•. Fails with ER_ROW_IS_REFERENCED_2 error code
InnoDB finds corresponding rows in the child table
ON UPDATE CASCADE
New foreign key value is present in parent table
Success
New foreign key value is not present in parent table
Fails with ER_NO_REFERENCED_ROW_2 error code
New foreign key value is NULL
Success
New foreign key value is present in parent table
This page is: Copyright © 2025 MariaDB. All rights reserved.
• Success. • Row in the parent table is updated. • Corresponding rows in the child table are also updated with the new foreign key value. If the child table has an update trigger, the trigger will not be executed for the update.
Success
$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.customers (
customer_id BIGINT AUTO_INCREMENT NOT NULL,
customer_name VARCHAR(500) NOT NULL,
customer_email VARCHAR(200),
PRIMARY KEY(customer_id)
);CREATE TABLE hq_sales.invoices (
invoice_id BIGINT AUTO_INCREMENT NOT NULL,
branch_id INT NOT NULL,
customer_id BIGINT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY(invoice_id),
CONSTRAINT fk_invoices_customers
FOREIGN KEY (customer_id) REFERENCES hq_sales.customers (customer_id)
ON DELETE RESTRICT
ON UPDATE RESTRICT
);INSERT INTO hq_sales.customers (customer_id, name)
VALUES
(1, 'John Doe'),
(2, 'Jane Doe');INSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 1, '2020-05-10 12:35:10', 1087.23, 'CREDIT_CARD'),
(1, 2, '2020-05-10 14:17:32', 1508.57, 'WIRE_TRANSFER');DELETE FROM hq_sales.customers
WHERE customer_id = 1;ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails
(`hq_sales`.`invoices`, CONSTRAINT `fk_invoices_customers`
FOREIGN KEY (`customer_id`) REFERENCES `customers` (`customer_id`))INSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 3, '2020-05-10 14:25:16', 227.15, 'CASH');ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`hq_sales`.`invoices`, CONSTRAINT `fk_invoices_customers`
FOREIGN KEY (`customer_id`) REFERENCES `customers` (`customer_id`))$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.customers (
customer_id BIGINT AUTO_INCREMENT NOT NULL,
customer_name VARCHAR(500) NOT NULL,
customer_email VARCHAR(200),
PRIMARY KEY(customer_id)
);CREATE TABLE hq_sales.invoices (
invoice_id BIGINT AUTO_INCREMENT NOT NULL,
branch_id INT NOT NULL,
customer_id BIGINT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY(invoice_id)
);ALTER TABLE hq_sales.invoices ADD CONSTRAINT fk_invoices_customers
FOREIGN KEY (customer_id) REFERENCES hq_sales.customers (customer_id)
ON DELETE RESTRICT
ON UPDATE RESTRICT;INSERT INTO hq_sales.customers (customer_id, name)
VALUES
(1, 'John Doe'),
(2, 'Jane Doe');INSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 1, '2020-05-10 12:35:10', 1087.23, 'CREDIT_CARD'),
(1, 2, '2020-05-10 14:17:32', 1508.57, 'WIRE_TRANSFER');DELETE FROM hq_sales.customers
WHERE customer_id = 1;ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails
(`hq_sales`.`invoices`, CONSTRAINT `fk_invoices_customers`
FOREIGN KEY (`customer_id`) REFERENCES `customers` (`customer_id`))INSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 3, '2020-05-10 14:25:16', 227.15, 'CASH');ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`hq_sales`.`invoices`, CONSTRAINT `fk_invoices_customers`
FOREIGN KEY (`customer_id`) REFERENCES `customers` (`customer_id`))$ mariadb --user=rootSELECT CONSTRAINT_NAME
FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = 'hq_sales'
AND TABLE_NAME = 'invoices'
AND CONSTRAINT_TYPE = 'FOREIGN KEY';+-----------------------+
| CONSTRAINT_NAME |
+-----------------------+
| fk_invoices_customers |
+-----------------------+ALTER TABLE hq_sales.invoices DROP FOREIGN KEY fk_invoices_customers;$ mariadb --user=rootSET SESSION foreign_key_checks=OFF;DELETE FROM hq_sales.customers
WHERE customer_id = 1;INSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 3, '2020-05-10 14:25:16', 227.15, 'CASH');SET SESSION foreign_key_checks=ON;<table_name>_ibfk_<constraint_count>2021-06-16 11:50:39 139702710404864 [ERROR] InnoDB: Possible reasons:
2021-06-16 11:50:39 139702710404864 [ERROR] InnoDB: (1) Table rename would cause two FOREIGN KEY constraints to have the same internal name in case-insensitive comparison.
2021-06-16 11:50:39 139702710404864 [ERROR] InnoDB: (2) Table `test`.`t3` exists in the InnoDB internal data dictionary though MySQL is trying to rename table `test`.`t2b` to it. Have you deleted the .frm file and not used DROP TABLE?
2021-06-16 11:50:39 139702710404864 [ERROR] InnoDB: If table `test`.`t3` is a temporary table #sql..., then it can be that there are still queries running on the table, and it will be dropped automatically when the queries end. You can drop the orphaned table inside InnoDB by creating an InnoDB table with the same name in another database and copying the .frm file to the current database. Then MySQL thinks the table exists, and DROP TABLE will succeed.Learn about AUTO_INCREMENT constraints in MariaDB Server. This section details how to automatically generate unique, sequential values for table columns, simplifying data management.
To define an AUTO_INCREMENT column, select an integer data type to accommodate the range of anticipated values. Common choices include INT, BIGINT, TINYINT, SMALLINT, and MEDIUMINT, depending on size requirements. Ensure the chosen type provides sufficient capacity to avoid overflow while optimizing storage efficiency.
MariaDB Enterprise Server supports AUTO_INCREMENT constraints:
A column with an AUTO_INCREMENT constraint can act as a table's primary key when a natural primary key is not available
Generated values for auto-increment columns are guaranteed to be unique and monotonically increasing
Auto-increment columns provide compatibility with schemas designed for MariaDB Enterprise Server and MySQL
Alternatively, MariaDB Enterprise Server can use as the primary key instead of columns with AUTO_INCREMENT constraints. Sequences are compliant with the SQL standard, while AUTO_INCREMENT constraints are not, so sequences are the better option for applications that require standard-compliant features.
AUTO_INCREMENT ColumnWhen designing a schema, AUTO_INCREMENT columns should use integer data types. The following types can be used:
To determine which type to use, consider the following points:
Do you want to be able to manually insert negative values? If not, then specify the UNSIGNED attribute for the column.
InnoDB can't generate negative AUTO_INCREMENT values, so it is only beneficial to use a signed integer column if you want the option to manually insert negative values, which would bypass the AUTO_INCREMENT handling.
How large will your table grow?
If your AUTO_INCREMENT column is being used as the table's primary key, then the maximum value for the chosen data type should be considered the maximum number of rows that can fit in the table:
If you want to give your table the most room to grow, then it would be best to choose BIGINT UNSIGNED.
Let's after confirming that the is InnoDB:
Connect to the server using MariaDB Client:
Confirm that the default storage engine is InnoDB by checking the using the statement:
If the database does not exist, then create the database for the table using the statement:
Create the table using the statement:
If a column is specified as AUTO_INCREMENT, then its value will be automatically generated. There are multiple ways to insert rows with these automatically generated values.
If the column is not specified, then InnoDB will automatically generate the value.
Let's insert a row into the table created in the section:
Connect to the server using MariaDB Client:
Insert a row with the statement, but do not specify the AUTO_INCREMENT column:
Select the same row with the statement to confirm that a value was automatically generated:
If the column's value is specified as 0, then InnoDB will automatically generate the value if the system variable does not contain NO_AUTO_VALUE_ON_ZERO.
Let's insert a row into the table created in the section:
Connect to the server using MariaDB Client:
Confirm that the session's value of the sql_mode system variable does not contain NO_AUTO_VALUE_ON_ZERO with the statement:
Insert a row with the statement, and specify the AUTO_INCREMENT column's value as 0:
Select the same row with the statement to confirm that a value was automatically generated:
If the column's value is specified as NULL, then InnoDB will automatically generate the value if the column is defined as NOT NULL.
Let's insert a row into the table created in the section:
Connect to the server using MariaDB Client:
Insert a row with the statement, and specify the AUTO_INCREMENT column's value as NULL:
Select the same row with the statement to confirm that a value was automatically generated:
After InnoDB inserts an automatically generated value into an AUTO_INCREMENT column, the application sometimes needs to know what value it inserted. For example, the application may need to use the value to insert a foreign key column in a dependent table. The function can be used to get the lasted inserted value for an AUTO_INCREMENT column without re-reading the row from the table.
Let's insert a row into the table created in the section and then use the function:
Connect to the server using MariaDB Client:
Insert a row with the statement, but do not specify the AUTO_INCREMENT column:
Execute the function to get the AUTO_INCREMENT value for the new row:
Select the same row with the statement to confirm that the AUTO_INCREMENT column has the same value:
When multiple rows are inserted into a table concurrently, InnoDB needs to be able to generate multiple values concurrently in a safe manner. It has several different modes that can be used to do this, and each mode has its own advantages and disadvantages.
InnoDB's AUTO_INCREMENT lock mode is configured with the system variable. Users can choose between 3 different values:
• In interleaved lock mode, InnoDB never holds a table-level lock while generating AUTO_INCREMENT values. • Interleaved lock mode is not safe to use if binlog_format is set to STATEMENT.|
The system variable configures the AUTO_INCREMENT Lock Mode for InnoDB.
Choose a configuration file for custom changes to system variables and options.
It is not recommended to make custom changes to Enterprise Server's default configuration files, because your custom changes can be overwritten by other default configuration files that are loaded after.
Ensure that your custom changes are read last by creating a custom configuration file in one of the included directories. Configuration files in included directories are read in alphabetical order. Use the z- prefix in the file name to ensure that your custom configuration file is read last.
Some example configuration file paths for different distributions are shown in the following table:
Set the system variable in the configuration file. It needs to be set in a group that will be read by MariaDB Server, such as [mariadb] or [server].
For example:
Restart the server:
A table's next AUTO_INCREMENT value can be set with the statement. The value is set using the AUTO_INCREMENT table option.
Let's alter the AUTO_INCREMENT value for the table created in the section and then insert a row into the table, so we can confirm that it uses the new value:
Connect to the server using MariaDB Client:
Alter the table's next AUTO_INCREMENT value with the statement:
Insert a row with the statement, but do not specify the AUTO_INCREMENT column:
Execute the function to get the AUTO_INCREMENT value for the new row:
Select the same row with the statement to confirm that the AUTO_INCREMENT column has the same value:
The offset and increment values can be configured by setting the system variables.
When Galera Cluster is used, the offset and increment values are managed automatically by default. They can be managed manually by disabling the system variable.
-9223372036854775808 - 9223372036854775807
0 - 18446744073709551615
9223372036854775807
18446744073709551615
-128 - 127
0 - 255
-32768 - 32767
0 - 65535
-8388608 - 8388607
0 - 16777215
-2147483648 - 2147483647
127
255
32767
65535
8388607
16777215
2147483647
0
• This value configures Traditional Lock Mode. • Don't use traditional lock mode. • Traditional lock mode performs very poorly. • In traditional lock mode, InnoDB holds a table-level lock while generating AUTO_INCREMENT values.
1
• This value configures Consecutive Lock Mode. • Consecutive lock mode is the default lock mode. • In consecutive lock mode, InnoDB holds a table-level lock while generating AUTO_INCREMENT values for statements that insert multiple new rows. However, InnoDB uses a lightweight internal lock to improve performance when generating an AUTO_INCREMENT value for statements that insert a single new row.
2
• This value configures Interleaved Lock Mode. • Interleaved lock mode is the recommended lock mode for best performance. • If Galera Cluster is being used, then interleaved lock mode must be configured.
CentOS RHEL Rocky Linux SLES
/etc/my.cnf.d/z-custom-mariadb.cnf
Debian Ubuntu
/etc/mysql/mariadb.conf.d/z-custom-mariadb.cnf
This page is: Copyright © 2025 MariaDB. All rights reserved.
0 - 4294967295
4294967295
$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'default_storage_engine';+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+CREATE DATABASE hq_sales;CREATE TABLE hq_sales.invoices (
invoice_id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
branch_id INT NOT NULL,
customer_id INT,
invoice_date DATETIME(6),
invoice_total DECIMAL(13, 2),
payment_method ENUM('NONE', 'CASH', 'WIRE_TRANSFER', 'CREDIT_CARD', 'GIFT_CARD'),
PRIMARY KEY(invoice_id)
);$ mariadb --user=rootINSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 1, '2020-05-10 12:35:10', 1087.23, 'CREDIT_CARD');SELECT invoice_id
FROM hq_sales.invoices
WHERE branch_id = 1
AND customer_id = 1
AND invoice_date = '2020-05-10 12:35:10';+------------+
| invoice_id |
+------------+
| 1 |
+------------+$ mariadb --user=rootSHOW SESSION VARIABLES
LIKE 'sql_mode';+---------------+-------------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------------------------------------------------------+
| sql_mode | STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+-------------------------------------------------------------------------------------------+INSERT INTO hq_sales.invoices
(invoice_id, branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(0, 1, 2, '2020-05-10 14:17:32', 1508.57, 'WIRE_TRANSFER');SELECT invoice_id
FROM hq_sales.invoices
WHERE branch_id = 1
AND customer_id = 2
AND invoice_date = '2020-05-10 14:17:32';+------------+
| invoice_id |
+------------+
| 2 |
+------------+$ mariadb --user=rootINSERT INTO hq_sales.invoices
(invoice_id, branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(NULL, 1, 3, '2020-05-10 14:25:16', 227.15, 'CASH');SELECT invoice_id
FROM hq_sales.invoices
WHERE branch_id = 1
AND customer_id = 3
AND invoice_date = '2020-05-10 14:25:16';+------------+
| invoice_id |
+------------+
| 3 |
+------------+$ mariadb --user=rootINSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 4, '2020-05-10 12:37:22', 104.19, 'CREDIT_CARD');SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 4 |
+------------------+SELECT invoice_id
FROM hq_sales.invoices
WHERE branch_id = 1
AND customer_id = 4
AND invoice_date = '2020-05-10 12:37:22';+------------+
| invoice_id |
+------------+
| 4 |
+------------+[mariadb]
...
innodb_autoinc_lock_mode = 2$ sudo systemctl restart mariadb$ mariadb --user=rootALTER TABLE hq_sales.invoices
AUTO_INCREMENT = 100;INSERT INTO hq_sales.invoices
(branch_id, customer_id, invoice_date, invoice_total, payment_method)
VALUES
(1, 5, '2020-05-10 12:43:19', 1105.98, 'CREDIT_CARD');SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 100 |
+------------------+SELECT invoice_id
FROM hq_sales.invoices
WHERE branch_id = 1
AND customer_id = 5
AND invoice_date = '2020-05-10 12:43:19';
+------------+
| invoice_id |
+------------+
| 100 |
+------------+