Menu

MySQL CHECK Constraints: Syntax and Examples

Learn MySQL CHECK constraint syntax, examples, NULL behavior, version support, and how to add constraints to existing tables.

Updated on

A MySQL CHECK constraint rejects a row when its condition evaluates to FALSE. Use it to enforce a rule such as a nonnegative price or a date range. In MySQL, CHECK constraints are enforced starting with version 8.0.16; earlier versions parsed the syntax but ignored the constraint. See the official MySQL 8.0.16 CHECK constraint announcement.

CHECK constraint syntax

MySQL supports column-level and table-level constraints. The general syntax is:

[CONSTRAINT [constraint_name]] CHECK (expression) [[NOT] ENFORCED]

A column-level constraint appears in the column definition and can refer only to that column. A table-level constraint appears separately and can refer to one or more columns. If you omit a name, MySQL generates one.

By default, a constraint is enforced. NOT ENFORCED creates the constraint but does not check it when rows change, so use that option only when you intentionally want a non-enforced constraint.

Create a table with CHECK constraints

This table uses column-level checks for nonnegative values and a table-level check to ensure the discount does not exceed the price:

CREATE TABLE products (
    product_id INT NOT NULL AUTO_INCREMENT,
    product_name VARCHAR(100) NOT NULL
        CHECK (CHAR_LENGTH(TRIM(product_name)) > 0),
    price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
    discount DECIMAL(10, 2) NOT NULL DEFAULT 0 CHECK (discount >= 0),
    PRIMARY KEY (product_id),
    CONSTRAINT products_discount_not_above_price
        CHECK (discount <= price)
);

price and discount use DECIMAL(10, 2): ten total digits with two fractional digits. Choose precision and scale to fit the required range and calculation rules; see the MySQL DECIMAL and NUMERIC guide.

The product_name definition combines NOT NULL with a CHECK: it rejects SQL NULL as well as an empty or space-only name. MySQL’s CHAR_LENGTH() counts characters, while LENGTH() counts bytes; see the MySQL string function reference for the distinction.

Insert a row that satisfies the constraints:

INSERT INTO products (product_name, price, discount)
VALUES ('Keyboard', 59.90, 10.00);

This row is rejected because the discount is greater than the price:

INSERT INTO products (product_name, price, discount)
VALUES ('Keyboard', 59.90, 70.00);

A CHECK condition must evaluate to TRUE or UNKNOWN for a row to pass; only FALSE violates it. Because a comparison with NULL evaluates to UNKNOWN, a CHECK constraint alone does not require a value. Pair it with a NOT NULL constraint when the column is mandatory.

Add a CHECK constraint to an existing table

Before adding a constraint, find and correct any existing rows that violate the rule. For example, if product_reviews has a rating column that must be between 1 and 5, check for out-of-range values:

SELECT product_id, rating
FROM product_reviews
WHERE rating < 1 OR rating > 5;

After correcting any returned rows, add the constraint:

ALTER TABLE product_reviews
ADD CONSTRAINT product_reviews_rating_range
CHECK (rating BETWEEN 1 AND 5);

MySQL validates existing rows when it adds an enforced CHECK constraint. The operation fails if any row evaluates to FALSE; see the MySQL ALTER TABLE documentation. If rating must also be present, make the column NOT NULL; a NULL rating makes the check condition UNKNOWN and passes the check.

Inspect CHECK constraints

Use SHOW CREATE TABLE to inspect a table definition and its constraint names:

SHOW CREATE TABLE products;

The result includes the CHECK expressions and whether each one is enforced. For the exact rules on permitted expressions and constraint evaluation, see MySQL’s CHECK constraint documentation.

To remove a check, use its constraint name from SHOW CREATE TABLE:

ALTER TABLE products
DROP CHECK products_discount_not_above_price;

Dropping a check removes that validation rule; it does not change existing rows.

Summary

Use a column-level CHECK for a rule about one column and a table-level CHECK when a rule compares multiple columns. Remember that CHECK accepts both TRUE and UNKNOWN, so add NOT NULL separately when a value is required.