Inspecting a table schema before changing queries, indexes, or migration code prevents type mismatches, missing defaults, and broken foreign-key assumptions from surfacing only after application traffic reaches the database.
MySQL and MariaDB expose table structure through several overlapping metadata commands. DESCRIBE provides a fast column summary, SHOW FULL COLUMNS adds collation, comments, and privileges, SHOW CREATE TABLE returns the declared DDL, SHOW INDEX lists key definitions, and SHOW TABLE STATUS reports storage details such as engine, row format, and table collation.
Metadata visibility still depends on the current account's privileges, and some fields differ between current MySQL and MariaDB releases. Triggers are stored separately from the table definition, and SHOW CREATE TABLE reflects the declared statement rather than every runtime detail, so a complete schema check should include column, index, foreign-key, and trigger metadata when table behavior is unclear.
$ mysql -u dbuser -p Enter password: mysql> USE appdb; Database changed mysql> SELECT DATABASE(); +------------+ | DATABASE() | +------------+ | appdb | +------------+ 1 row in set (0.00 sec)
mysql> SHOW TABLES LIKE 'orders'; +--------------------------+ | Tables_in_appdb (orders) | +--------------------------+ | orders | +--------------------------+ 1 row in set (0.00 sec)
Use backticks for identifiers that collide with reserved words or include special characters, such as `order` or `user-profile`.
mysql> DESCRIBE orders; +--------------+---------------+------+-----+-------------------+-----------------------------------------------+ | Field | Type | Null | Key | Default | Extra | +--------------+---------------+------+-----+-------------------+-----------------------------------------------+ | id | int | NO | PRI | NULL | auto_increment | | customer_id | int | NO | MUL | NULL | | | order_status | varchar(20) | NO | | pending | | | total | decimal(10,2) | NO | | NULL | | | created_at | timestamp | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED | | updated_at | timestamp | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP | +--------------+---------------+------+-----+-------------------+-----------------------------------------------+ 6 rows in set (0.00 sec)
DESCRIBE is a shortcut for SHOW COLUMNS FROM in both MySQL and MariaDB.
mysql> SHOW FULL COLUMNS FROM orders; +--------------+---------------+--------------------+------+-----+-------------------+-----------------------------------------------+---------------------------------+----------------+ | Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment | +--------------+---------------+--------------------+------+-----+-------------------+-----------------------------------------------+---------------------------------+----------------+ | id | int | NULL | NO | PRI | NULL | auto_increment | select,insert,update,references | | | customer_id | int | NULL | NO | MUL | NULL | | select,insert,update,references | | | order_status | varchar(20) | utf8mb4_unicode_ci | NO | | pending | | select,insert,update,references | workflow state | | total | decimal(10,2) | NULL | NO | | NULL | | select,insert,update,references | | | created_at | timestamp | NULL | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED | select,insert,update,references | | | updated_at | timestamp | NULL | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP | select,insert,update,references | | +--------------+---------------+--------------------+------+-----+-------------------+-----------------------------------------------+---------------------------------+----------------+ 6 rows in set (0.00 sec)
mysql> SHOW CREATE TABLE orders\G
*************************** 1. row ***************************
Table: orders
Create Table: CREATE TABLE `orders` (
`id` int NOT NULL AUTO_INCREMENT,
`customer_id` int NOT NULL,
`order_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending' COMMENT 'workflow state',
`total` decimal(10,2) NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_orders_customer_id` (`customer_id`),
CONSTRAINT `fk_orders_customer` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)
SHOW CREATE TABLE is the fastest way to inspect the table's declared DDL, but triggers are separate objects and some engine-level runtime details still need SHOW TABLE STATUS or information_schema.
mysql> SHOW INDEX FROM orders; +--------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +--------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | orders | 0 | PRIMARY | 1 | id | A | 1 | NULL | NULL | | BTREE | | | YES | NULL | | orders | 1 | idx_orders_customer_id | 1 | customer_id | A | 1 | NULL | NULL | | BTREE | | | YES | NULL | +--------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ 2 rows in set (0.00 sec)
Current MySQL adds Visible and Expression columns here, while current MariaDB returns Ignored instead. Cardinality is an optimizer estimate, not an exact row count.
mysql> SHOW TABLE STATUS LIKE 'orders'\G
*************************** 1. row ***************************
Name: orders
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 1
Avg_row_length: 16384
Data_length: 16384
Max_data_length: 0
Index_length: 16384
Data_free: 0
Auto_increment: 2
Create_time: 2026-04-09 22:18:37
Update_time: 2026-04-09 22:18:37
Check_time: NULL
Collation: utf8mb4_unicode_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
For InnoDB tables, Update_time can be NULL or lag behind recent writes, so treat Engine, Row_format, Collation, and Auto_increment as the higher-signal fields.
mysql> SELECT
-> kcu.CONSTRAINT_NAME,
-> kcu.COLUMN_NAME,
-> kcu.REFERENCED_TABLE_NAME,
-> kcu.REFERENCED_COLUMN_NAME,
-> rc.UPDATE_RULE,
-> rc.DELETE_RULE
-> FROM information_schema.KEY_COLUMN_USAGE AS kcu
-> JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc
-> ON rc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
-> AND rc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
-> WHERE kcu.TABLE_SCHEMA = DATABASE()
-> AND kcu.TABLE_NAME = 'orders'
-> AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
-> ORDER BY kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION;
+--------------------+-------------+-----------------------+------------------------+-------------+-------------+
| CONSTRAINT_NAME | COLUMN_NAME | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME | UPDATE_RULE | DELETE_RULE |
+--------------------+-------------+-----------------------+------------------------+-------------+-------------+
| fk_orders_customer | customer_id | customers | id | NO ACTION | NO ACTION |
+--------------------+-------------+-----------------------+------------------------+-------------+-------------+
1 row in set (0.00 sec)
For the same default foreign-key action, current MySQL commonly reports NO ACTION while current MariaDB reports RESTRICT.
mysql> SHOW TRIGGERS WHERE `Table` = 'orders'\G
*************************** 1. row ***************************
Trigger: orders_before_insert
Event: INSERT
Table: orders
Statement: BEGIN
IF NEW.order_status = '' THEN
SET NEW.order_status = 'pending';
END IF;
END
Timing: BEFORE
Created: 2026-04-09 22:18:37.81
##### snipped #####
Use SHOW CREATE TRIGGER orders_before_insert\G when the full trigger body, definer, or SQL mode needs inspection.