Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 4098 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Server

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

MariaDB Server Documentation

Explore MariaDB Server, the powerful open-source relational database. This comprehensive documentation covers installation, deployment, usage, security, and advanced topics to help you master MariaDB.

Quickstart Guides

Get started quickly with MariaDB Server using these quickstart guides. Follow step-by-step instructions to install, configure, and begin using MariaDB for your projects.

Server Usage

Learn how to effectively use MariaDB Server. This section covers SQL statements, built-in functions, client utilities, and best practices for daily database operations.

Server Management

Effectively managing your MariaDB Server is key to ensuring its reliability, performance, and security. This section serves as your central hub for all aspects of MariaDB Server management.

Security

Secure your MariaDB Server. This section provides comprehensive guidance on user management, encryption, authentication, auditing, and other crucial security measures.

Architecture

Understand MariaDB Server's architecture. Explore its components, storage engines, and how they interact to provide a high-performance, reliable database solution.

Clients & Utilities

Discover MariaDB Server's clients and utilities. This section guides you through tools for connecting, managing, and interacting with your database, from command-line clients to graphical interfaces.

HA & Performance

Optimize MariaDB Server for high availability and performance. Learn about replication, clustering, load balancing, and configuration tuning for robust and efficient database solutions.

Reference

Access the comprehensive MariaDB Server reference. Find detailed documentation on SQL syntax, data types, functions, system variables, and other technical specifications.

Quickstart Guides

Get started quickly with MariaDB Server using these quickstart guides. Follow step-by-step instructions to install, configure, and begin using MariaDB for your projects.

Installing MariaDB Server Guide

Official MariaDB Server install guide: Linux apt/dnf/yum commands, mariadb-secure-installation setup, systemctl status/start checks, Windows .msi installer.

Adding & Changing Data Guide

This guide provides a walkthrough of the INSERT, UPDATE, and DELETE statements, demonstrating how to add, modify, and remove data in tables.

Essential Queries Guide

Learn how to perform essential SQL operations such as creating tables, inserting data, and using aggregate functions like MAX, MIN, and AVG.

Basics Guide

Complete MariaDB basics guide: connect with mariadb -u/-p/-h, CREATE DATABASE/USE, CREATE TABLE with AUTO_INCREMENT, INSERT/SELECT/UPDATE/DELETE commands.

Altering Tables Guide

Learn how to modify existing table structures using the ALTER TABLE statement, including adding columns, changing types, and managing indexes.

Connecting to MariaDB Guide

This guide details how to connect to a MariaDB server using the command-line client, covering options for host, user, password, and protocol.

Troubleshooting Connection Issues Guide

Diagnose and fix common MariaDB Server connection problems, such as "Can't connect to local server" and access-denied errors, with step-by-step troubleshooting.

Doing Time Guide

Understand how to work with date and time values in MariaDB, including data types like DATETIME and TIMESTAMP, and useful temporal functions.

Importing Data Guide

Learn how to efficiently import data into MariaDB tables from external files using the LOAD DATA INFILE statement.

Essentials of an Index Guide

This guide provides a conceptual overview of database indexes, explaining their purpose, different types, and when to use them for optimization.

Getting Started with Indexes Guide

Definitive MariaDB indexes guide: PRIMARY KEY, UNIQUE INDEX, INDEX, FULLTEXT types, CREATE/ALTER TABLE syntax, CREATE INDEX, SHOW INDEX, and EXPLAIN.

Joining Tables with JOIN Clauses

This guide introduces the different types of JOINs (INNER, LEFT, RIGHT, CROSS) and demonstrates how to combine data from multiple tables.

Advanced Joins

Explore complex join scenarios. This guide covers filtering joined data with WHERE clauses, handling dates, and aggregating results from multiple tables for deeper analysis.

Configuring MariaDB for Remote Client Access Guide

Configure MariaDB Server to accept remote connections by setting bind-address, granting privileges for remote users, and opening the right firewall rules.

Getting Data Guide

This guide explains the SELECT statement in detail, covering how to retrieve, filter, limit, and sort data from your MariaDB database.

Basic SQL Statements Guide

A quick reference for core SQL statements including DDL (CREATE, DROP), DML (INSERT, UPDATE, DELETE), and TCL (COMMIT, ROLLBACK) commands.

Basic SQL Debugging Guide

This guide offers conventions and practical tips for designing SQL queries that are easier to read, understand, and debug.

MariaDB String Functions Guide

This guide goes through several built-in string functions in MariaDB, grouping them by similar features, and providing examples of how they might be used.

Restoring Data from Dump Files Guide

Restore MariaDB data from mariadb-dump backup files using the mariadb client, including how to selectively restore a single table.

Changing Times in MariaDB

This guide explores MariaDB functions for performing calculations and modifications on date and time values, like DATE_ADD and DATE_SUB.

System & Status Variables Guide

This guide indicates where the various system and status variables of MariaDB Server are found.

Making Backups with mariadb-dump Guide

Create logical backups of MariaDB databases with the mariadb-dump utility, covering how to back up all databases, specific databases, or individual tables.

A MariaDB Primer Guide

A beginner-friendly primer on using the mariadb command-line client to log in, create databases, and execute basic SQL commands.

Creating & Using Views Guide

Discover how to create and use views to simplify complex queries, restrict data access, and present a specific perspective of your data.

Database Applications

This section offers advice on writing and maintaining applications that use databases, covering schema design, code practices, and testing.

Introduction & Background

This section provides an introduction to developing database-backed applications with MariaDB, discussing maintenance, upgrades, and separation of concerns.

Introduction

When designing database-based applications, one aspect that might always be considered at first is how you are supposed to maintain these applications; here, we mean maintenance in the sense of application code and database schemas being upgraded and how this can be done with minimum downtime and effort.

This document aims to look at some important aspects of this, from database schema design to application code. Most of these are not strict rules, but rather aspects to consider when working with applications. The document does not cover general application code aspects, only the aspects that deal with the database part of applications.

Background to Relational Database Applications

Relational database systems, more or less all of them using the SQL query language, have been around since the early 1980s, and things have changed a lot over that time. One aspect that applications using relational databases introduced was the separation of the application, dealing with logic, presentation, user interaction and similar aspects on one hand and the database structure and design on the other.

With relational databases came the relational database modelling and eventually the different normal forms of database design. Much of this has relaxed these days, but there are still things to consider here.

The introduction of logic in the database layer, such as stored procedures, triggers and other aspects, is somewhat blurring the line between code and data, but the general rules still hold.

Basics

Grasp the basics of using MariaDB Server. This section introduces fundamental concepts, common SQL commands, and essential operations to get you started with your database.

Basic Queries

This guide covers the fundamentals of creating database structures, inserting data, and retrieving information using the default MariaDB client.

The introductory SQL tutorials now live in the Quickstart Guides:

  • A MariaDB Primer

  • Basic SQL Statements

  • Essential Queries

  • Basic SQL Debugging

  • String Functions

Backup & Restore

Learn to back up and restore MariaDB Server databases. This section covers essential strategies and tools to ensure data safety and quick recovery from potential data loss.

Backup and Restore Overview

Complete MariaDB backup and recovery guide. Complete resource for backup methods, mariabackup usage, scheduling, and restoration for production use.

Forming a Backup Strategy

Learn how to design a robust backup strategy tailored to your business needs, balancing recovery time objectives and data retention policies.

Backup Optimization

Discover techniques to optimize your backup processes, including multithreading, incremental backups, and leveraging storage snapshots.

MariaDB Enterprise Backup

This page details MariaDB Enterprise Backup, an enhanced version of mariadb-backup with enterprise-specific optimizations and support.

mariadb-backup

Get an overview of MariaDB Backup. This section introduces the hot physical backup tool, explaining its capabilities for efficient and consistent backups of your MariaDB Server.

Point-In-Time Recovery (InnoDB Log Archiving)

Perform point-in-time recovery in MariaDB by replaying archived InnoDB write-ahead logs at startup to restore the server to a specific Log Sequence Number (LSN).

Replication as a Backup Solution

Explore how to use replication as part of your backup strategy, allowing you to offload backup tasks to a replica server to reduce load on the primary.

Backup and Restore via dbForge Studio

Learn how to use dbForge Studio, a GUI tool, to perform backup and restore operations for MariaDB databases visually.

Partitioning Tables

Optimize large tables in MariaDB Server with partitioning. Learn how to divide tables into smaller, manageable parts for improved performance, easier maintenance, and scalability.

Partitioning Overview

Complete Partitioning Overview guide for MariaDB. Complete reference documentation for implementation, configuration, and usage for production use.

Partition Pruning and Selection

Understand how the optimizer automatically prunes irrelevant partitions and how to explicitly select partitions in your queries for efficiency.

Partition Maintenance

Discover administrative tasks for managing partitions, such as adding, dropping, reorganizing, and coalescing them to keep your data optimized.

Partitioning Types Overview

An introduction to the various partitioning strategies available in MariaDB, helping you choose the right method for your data distribution needs. For a complete list of partitioning types, see this page.

Partitioning Limitations

This page outlines constraints when using partitioning, such as the maximum number of partitions and restrictions on foreign keys and query cache usage.

Partitions Files

Learn how MariaDB stores partitioned tables on the filesystem, typically creating separate .ibd files for each partition when using InnoDB.

Partitions Metadata

Understand how to retrieve metadata about partitions using the INFORMATION_SCHEMA.PARTITIONS table to monitor row counts and storage usage.

Partitioning Types

Explore different partitioning types for MariaDB Server tables. Understand range, list, hash, and key partitioning to optimize data management and improve query performance.

Partitioning Types Overview

An introduction to the various partitioning strategies available in MariaDB, helping you choose the right method for your data distribution needs.

HASH Partitioning Type

Learn about HASH partitioning, which distributes data based on a user-defined expression to ensure an even spread of rows across partitions.

KEY Partitioning Type

Understand KEY partitioning, similar to HASH but using MariaDB's internal hashing function on one or more columns to distribute data.

LINEAR HASH Partitioning Type

Explore LINEAR HASH partitioning, a variation of HASH that uses a powers-of-two algorithm for faster partition management at the cost of distribution.

LINEAR KEY Partitioning Type

Learn about LINEAR KEY partitioning, which combines the internal key hashing with a linear algorithm for efficient partition handling.

LIST Partitioning Type

Understand LIST partitioning, where rows are assigned to partitions based on whether a column value matches one in a defined list of values.

RANGE COLUMNS and LIST COLUMNS Partitioning Types

Discover these variants that allow partitioning based on multiple columns and non-integer types, offering greater flexibility than standard RANGE/LIST.

RANGE Partitioning Type

The RANGE partitioning type assigns rows to partitions based on whether column values fall within contiguous, non-overlapping ranges.

Stored Routines

Automate tasks in MariaDB Server with stored routines. Learn to create and manage stored procedures and functions for enhanced database efficiency and code reusability.

Stored Procedures

Master stored procedures in MariaDB Server. This section covers creating, executing, and managing these powerful routines to encapsulate complex logic and improve application performance.

Stored Functions

Utilize stored functions in MariaDB Server. This section details creating, using, and managing user-defined functions to extend SQL capabilities and streamline data manipulation.

Binary Logging of Stored Routines

When binary logging is enabled, stored routines may require special handling (like SUPER privileges) if they are non-deterministic, to ensure consistent replication.

Stored Routine Limitations

Stored routines have specific restrictions, such as prohibiting certain SQL statements (e.g., LOAD DATA) and disallowing result sets in functions.

DBMS_OUTPUT

The DBMS_OUTPUT plugin provides Oracle-compatible output buffering functions (like PUT_LINE), allowing stored procedures to send messages to the client.

Stored Procedures

Master stored procedures in MariaDB Server. This section covers creating, executing, and managing these powerful routines to encapsulate complex logic and improve application performance.

Stored Procedure Overview

Stored procedures are precompiled collections of SQL statements stored on the server, allowing for encapsulated logic, parameterized execution, and improved application performance.

CREATE PROCEDURE

Complete CREATE PROCEDURE guide for MariaDB. Complete reference documentation for implementation, configuration, and usage with comprehensive examples and.

ALTER PROCEDURE

The ALTER PROCEDURE statement modifies the characteristics of an existing stored procedure, such as its security context or comment, without changing its logic.

DROP PROCEDURE

The DROP PROCEDURE statement permanently removes a stored procedure and its associated privileges from the database.

Stored Functions

Utilize stored functions in MariaDB Server. This section details creating, using, and managing user-defined functions to extend SQL capabilities and streamline data manipulation.

Stored Function Overview

A Stored Function is a set of SQL statements that can be called by name, accepts parameters, and returns a single value, enhancing SQL with custom logic.

Stored Aggregate Functions

Stored Aggregate Functions allow users to create custom aggregate functions that process a sequence of rows and return a single summary result.

Stored Routine Privileges

This page explains the privileges required to create, alter, execute, and drop stored routines, including the automatic grants for creators.

DROP FUNCTION

The DROP FUNCTION statement removes a stored function from the database, deleting its definition and associated privileges.

Stored Function Limitations

This page details the restrictions on stored functions, such as the inability to return result sets or use transaction control statements.

Installing MariaDB Server Guide

Official MariaDB Server install guide: Linux apt/dnf/yum commands, mariadb-secure-installation setup, systemctl status/start checks, Windows .msi installer.

This guide provides step-by-step instructions for installing MariaDB Server on various operating systems, including package updates and security settings.

The most common way to install MariaDB on Linux is through your system's package manager.

Steps:

  1. Update Package List:

    Before installing, it's a good practice to update your package index.

Essentials of an Index Guide

This guide provides a conceptual overview of database indexes, explaining their purpose, different types, and when to use them for optimization.

An index on Last_Name organizes the records by surname, enhancing search efficiency without altering the original table order. Indices can be created for any column, such as ID or first name, to enable quick lookups based on different criteria.

Imagine you've created a table with the following rows:

+----+------------+-----------+-------------------------+---------------------------+--------------+
| ID | First_Name | Last_Name | Position                | Home_Address              | Home_Phone   |
+----+------------+-----------+-------------------------+---------------------------+--------------+
|  1 | Mustapha   | Mond      | Chief Executive Officer | 692 Promiscuous Plaza     | 326-555-3492 |
|  2 | Henry      | Foster    | Store Manager           | 314 Savage Circle         | 326-555-3847 |
|  3 | Bernard    | Marx      | Cashier                 | 1240 Ambient Avenue       | 326-555-8456 |
|  4 | Lenina     | Crowne    | Cashier                 | 281 Bumblepuppy Boulevard | 328-555-2349 |
|  5 | Fanny      | Crowne    | Restocker               | 1023 Bokanovsky Lane      | 326-555-6329 |
|  6 | Helmholtz  | Watson    | Janitor                 | 944 Soma Court            | 329-555-2478 |
+----+------------+-----------+-------------------------+---------------------------+--------------+

Now, imagine you've been asked to return the home phone of Fanny Crowne. Without indexes, the only way to do it is to go through every row until you find the matching first name and surname. Now imagine there are millions of records and you can see that, even for a speedy database server, this is highly inefficient.

The answer is to sort the records. If they were stored in alphabetical order by surname, even a human could quickly find a record amongst a large number. But we can't sort the entire record by surname. What if we want to also look a record by ID, or by first name? The answer is to create separate indexes for each column we wish to sort by. An index simply contains the sorted data (such as surname), and a link to the original record.

For example, an index on Last_Name:

and an index on Position

would allow you to quickly find the phone numbers of all the cashiers, or the phone number of the employee with the surname Marx, very quickly.

Where possible, you should create an index for each column that you search for records by, to avoid having the server read every row of a table.

See and for more information.

This page is licensed: CC BY-SA / Gnu FDL

Restoring Data from Dump Files Guide

Restore MariaDB data from mariadb-dump backup files using the mariadb client, including how to selectively restore a single table.

This guide explains how to restore your MariaDB data from backup files created with mariadb-dump. Learn the basic restoration process using the mariadb client and a specific technique for selectively restoring a single table while minimizing data loss on other tables.

It's important to understand that mariadb-dump is used for creating backup (dump) files, while the mariadb client utility is used for restoring data from these files. The dump file contains SQL statements that, when executed, recreate the database structure and/or data.

To restore a dump file, you direct the mariadb client to execute the SQL statements contained within the file.

Canary Testing

Explore strategies for safely testing schema and application changes using canary deployments, replication, and features like invisible columns.

For canary testing new versions of an application, there are some tools to work with, but it has to be said that this is hardly ever 100% clear. If we assume that the advice above has been followed to some extent, then the following are some tools to work with.

In a MariaDB instance, there is the concept of a database, which is similar to a schema. A database is a kind of namespace, which means that an object, say a table, in one database may have the same name as an object in some other database in the same instance. Given this, databases are a key to allowing somewhat different schemas to coexist, which in turn means that it is good practice not to hard-code the database name in applications or schema objects, unless this makes sense.

Views are an excellent way of hiding complexities, and a good way of dealing with this is to have a separate database for a new version with VIEWs referencing the actual data in some other database.

When adding a new version of the schema/application, it is sometimes necessary to migrate the data to the new schema and have a VIEW in the "old" schema referencing the new one. A view is not always necessary in this case, but any added columns have to be handled by a trigger or by a sensible default.

Server Usage

Learn how to effectively use MariaDB Server. This section covers SQL statements, built-in functions, client utilities, and best practices for daily database operations.

Basics

Grasp the basics of using MariaDB Server. This section introduces fundamental concepts, common SQL commands, and essential operations to get you started with your database.

Backup & Restore

Learn to back up and restore MariaDB Server databases. This section covers essential strategies and tools to ensure data safety and quick recovery from potential data loss.

Manage tables in MariaDB Server. This section details creating, altering, and dropping tables, along with understanding data types and storage engines for optimal database design.

Optimize large tables in MariaDB Server with partitioning. Learn how to divide tables into smaller, manageable parts for improved performance, easier maintenance, and scalability.

Automate tasks in MariaDB Server with stored routines. Learn to create and manage stored procedures and functions for enhanced database efficiency and code reusability.

Understand MariaDB Server's storage engines. Explore the features and use cases of InnoDB, Aria, MyISAM, and other engines to choose the best option for your specific data needs.

Automate database actions with triggers and events in MariaDB Server. Learn to define automatic responses to data modifications and schedule tasks for efficient database management.

Extend MariaDB Server's capabilities with user-defined functions (UDFs). Learn how to create and implement custom functions to perform specialized operations directly within your SQL queries.

Learn to use views in MariaDB Server. This section explains how to create virtual tables from query results, simplifying complex queries and enhancing data security and abstraction.

mariadb-backup

Get an overview of MariaDB Backup. This section introduces the hot physical backup tool, explaining its capabilities for efficient and consistent backups of your MariaDB Server.

An introduction to the mariadb-backup utility, detailing its features, installation process, and support for hot online backups of InnoDB tables.

A comprehensive reference for all command-line options available in mariadb-backup, covering backup, prepare, and restore operations.

Point-In-Time Recovery (PITR, mariadb-backup)

Explains how to restore (recover) to a specific point in time. Point-in-time recovery is often referred to as PITR.

Recovering from a backup can restore the data directory at a specific point in time, but it does not restore the binary log. In a point-in-time recovery, start by restoring the data directory from a full or incremental backup, then use the mysqlbinlog utility to restore the binary log data to a specific point in time.

Run the following commands as root unless indicated otherwise.

1

Find the binary log position to restore to.

When MariaDB Backup runs on a MariaDB Server with binary logs enabled (which is a prerequisite for PITR), it stores binary log information in the mariadb_backup_binlog_info (or xtrabackup_binlog_info in older releases) file. Consult this file to find the name of the binary log position to use. In the following example, the log position is 321:

2

Configure a new data directory.

Update the configuration file (for instance, my.cnf) to use a new data directory.

3

Restore the backup.

Restore from the backup .

4

Start the database server.

Start MariaDB Server.

5

Create a script using mysqlbinlog.

Use the mysqlbinlog utility to create an SQL script, using the binary log file in the old data directory, the start position in the xtrabackup_binlog_info file, and the date and time you want to restore to. Issue the following command as a regular user:

6

Run the script.

In the new data directory, run the script created in the previous step:

  • — an alternative PITR procedure that replays archived InnoDB write-ahead logs instead of binary logs. Available from MariaDB 13.0.

Restoring Individual Tables and Partitions (mariadb-backup)

Restore specific tables from a backup. Learn the process of importing individual .ibd files to recover specific tables without restoring the whole database.

mariadb-backup was previously called mariabackup.

When using mariadb-backup, you don't necessarily need to restore every table and/or partition that was backed up. Even if you're starting from a full backup, it is certainly possible to restore only certain tables and/or partitions from the backup, as long as the table or partition involved is in an InnoDB file-per-table tablespace. This page documents how to restore individual tables and partitions.

For a complete list of mariadb-backup options, .

For a detailed description of mariadb-backup functionality, .

Preparing the Backup

Before you can restore from a backup, you first need to prepare it to make the data files consistent. You can do so with the --prepare option.

The ability to restore individual tables and partitions relies on InnoDB's transportable tablespaces. For MariaDB to import tablespaces like these, InnoDB looks for a file with a .cfg extension. For mariadb-backup to create these files, you also need to add the --export option during the prepare step.

For example, you might execute the following command:

If this operation completes without error, then the backup is ready to be restored.

Note

mariadb-backup did not support the --export option to begin with. See about that. In earlier versions of MariaDB, this means that mariadb-backup could not create .cfg files for InnoDB file-per-table tablespaces during the --prepare stage. You can still import file-per-table tablespaces without the .cfg files in many cases, so it may still be possible in those versions to restore partial backups or to restore individual tables and partitions with just the .ibd files. If you have a full backup and you need to create .cfg files for InnoDB file-per-table tablespaces, then you can do so by preparing the backup as usual without the --export option, and then restoring the backup, and then starting the server. At that point, you can use the server's built-in features to copy the transportable tablespaces.

The restore process for restoring individual tables and/or partitions is quite different than the process for full backups.

Rather than using the --copy-back or the --move-back, each individual InnoDB file-per-table tablespace file will have to be manually imported into the target server. The process that is used to restore the backup will depend on whether partitioning is involved.

To restore individual non-partitioned tables from a backup, find the .ibd and .cfg files for the table in the backup, and then import them using the Importing Transportable Tablespaces for Non-partitioned Tables process.

To restore individual partitions or partitioned tables from a backup, find the .ibd and .cfg files for the partitions in the backup, and then import them using the process.

This page is licensed: CC BY-SA / Gnu FDL

Files Backed Up by mariadb-backup

List of file types included in a backup. Understand which data files, logs, and configuration files are preserved during the backup process.

mariadb-backup was previously called mariabackup.

Files Included in Backup

mariadb-backup backs up the files listed below.

InnoDB Data Files

mariadb-backup backs up the following InnoDB data files:

  • InnoDB system tablespace

  • InnoDB file-per-table tablespaces

MyRocks Data Files

mariadb-backup will back up tables that use the MyRocks storage engine. This data is located in the directory defined by the rocksdb_datadir system variable. mariadb-backup backs this data up by performing a checkpoint using the rocksdb_create_checkpoint system variable.

mariadb-backup will back up tables that use the MyRocks storage engine.

Other Data Files

mariadb-backup also backs up files with the following extensions:

  • frm

  • isl

  • MYD

  • MYI

  • MAD

  • MAI

  • MRG

  • TRG

  • TRN

  • ARM

  • ARZ

  • CSM

  • CSV

  • opt

  • par

Files Excluded From Backup

mariadb-backup does not back up the files listed below.

  • InnoDB Temporary Tablespaces

  • Binary logs

  • Relay logs

This page is licensed: CC BY-SA / Gnu FDL

Using Encryption and Compression Tools With mariadb-backup

Secure and compress backup streams. Learn to pipe backup output to tools like GPG and GZIP for encryption and storage efficiency.

mariadb-backup was previously called mariabackup.

mariadb-backup supports streaming to stdout with the --stream=xbstream option. This option allows easy integration with popular encryption and compression tools. Below are several examples.

For a complete list of mariadb-backup options, .

For a detailed description of mariadb-backup functionality, .

Encrypting and Decrypting Backup With openssl

The following example creates an AES-encrypted backup, protected with the password "mypass" and stores it in a file "backup.xb.enc":

mariadb-backup --user=root --backup --stream=xbstream  | openssl  enc -aes-256-cbc -k mypass > backup.xb.enc

To decrypt and unpack this backup into the current directory, the following command can be used:

openssl  enc -d -aes-256-cbc -k mypass -in backup.xb.enc | mbstream -x

Compressing and Decompressing Backup With gzip

This example compresses the backup without encrypting:

mariadb-backup --user=root --backup --stream=xbstream | gzip > backupstream.gz

We can decompress and unpack the backup as follows:

gunzip -c backupstream.gz | mbstream -x

Compressing and Encrypting Backup, Using gzip and openssl

This example adds a compression step before the encryption, otherwise looks almost identical to the previous example:

We can decrypt, decompress and unpack the backup as follow (note gzip -d in the pipeline):

7zip archiver is a popular utility (especially on Windows) that supports reading from standard output, with the --si option, and writing to stdout with the -so option, and can thus be used together with mariadb-backup.

Compressing backup with the 7z command line utility works as follows:

Uncompress and unpack the archive with

7z also has builtin AES-256 encryption. To encrypt the backup from the previous example using password SECRET, add -pSECRET to the 7z command line.

Compress

Decompress, unpack

Encryption

Decrypt, unpack

Most of the described tools also provide a way to enter a passphrase interactively (although 7zip does not seem to work well when reading input from stdin). Please consult documentation of the tools for more info.

By default files like xtrabackup_checkpoints are also written to the output stream only, and so would not be available for taking further incremental backups without prior extraction from the compressed or encrypted stream output file.

To avoid this these files can additionally be written to a directory that can then be used as input for further incremental backups using the --extra-lsndir=... option.

See also e.g: Combining incremental backups with streaming output

This page is licensed: CC BY-SA / Gnu FDL

Tables

Manage tables in MariaDB Server. This section details creating, altering, and dropping tables, along with understanding data types and storage engines for optimal database design.

Copying Tables Between Databases and Servers

This guide explains various methods for copying tables between MariaDB databases and servers, including using FLUSH TABLES FOR EXPORT and mysqldump.

ALTER TABLE

Complete ALTER TABLE guide for MariaDB. Complete syntax for modifying columns, indexes, constraints, and table properties with comprehensive examples.

CREATE TABLE

Complete guide to creating tables in MariaDB. Complete CREATE TABLE syntax for data types, constraints, indexes, and storage engines for production use.

DROP TABLE

Complete DROP TABLE syntax: TEMPORARY, IF EXISTS, WAIT/NOWAIT, RESTRICT/CASCADE options, metadata locks, atomic DROP, and replication behavior.

Data Types

Comprehensive MariaDB data types reference. Complete guide for numeric, string, date/time, spatial, and JSON types with storage specifications.

Storage Engines

Understand MariaDB Server's storage engines. Explore the features and use cases of InnoDB, Aria, MyISAM, and other engines to choose the best option for your specific data needs.

The task-oriented table tutorials now live in the :

Partition Pruning and Selection

Understand how the optimizer automatically prunes irrelevant partitions and how to explicitly select partitions in your queries for efficiency.

When a WHERE clause is related to the partitioning expression, the optimizer knows which partitions are relevant for the query. Other partitions will not be read. This optimization is called partition pruning.

EXPLAIN PARTITIONS can be used to know which partitions are read for a given query. A column called partitions will contain a comma-separated list of the accessed partitions. For example:

EXPLAIN PARTITIONS SELECT * FROM orders WHERE id < 15000000;
+------+-------------+--------+------------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+--------+------------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | orders | p0,p1      | range | PRIMARY       | PRIMARY | 4       | NULL |    2 | Using where |
+------+-------------+--------+------------+-------+---------------+---------+---------+------+------+-------------+

Sometimes the WHERE clause does not contain the necessary information to use partition pruning, or the optimizer cannot infer this information. However, we may know which partitions are relevant for the query. We can force MariaDB to only access the specified partitions by adding a PARTITION clause. This feature is called partition selection. For example:

SELECT * FROM orders PARTITION (p3) WHERE user_id = 50;
SELECT * FROM orders PARTITION (p2,p3) WHERE user_id >= 40;

The PARTITION clause is supported for all DML statements:

  • SELECT

  • INSERT

  • UPDATE

  • DELETE

Partition Pruning and Triggers

In general, partition pruning is applied to statements contained in triggers.

However, note that if a BEFORE INSERT or BEFORE UPDATE trigger is defined on a table, MariaDB doesn't know in advance if the columns used in the partitioning expression are changed. For this reason, it is forced to lock all partitions.

This page is licensed: CC BY-SA / Gnu FDL

Partitioning Types Overview

An introduction to the various partitioning strategies available in MariaDB, helping you choose the right method for your data distribution needs.

A partitioning type determines how a partitioned table's rows are distributed across partitions. Some partition types require the user to specify a partitioning expression that determines in which partition a row are stored.

The size of individual partitions depends on the partitioning type. Read and write performance are affected by the partitioning expression. Therefore, these choices should be made carefully.

Partitioning Types

MariaDB supports the following partitioning types:

  • RANGE

This page is licensed: CC BY-SA / Gnu FDL

HASH Partitioning Type

Learn about HASH partitioning, which distributes data based on a user-defined expression to ensure an even spread of rows across partitions.

HASH partitioning is a form of in which the server takes care of the partition in which to place the data, ensuring an even distribution among the partitions.

It requires a column value, or an expression based on a column value, which is hashed, as well as the number of partitions into which to divide the table.

  • partitioning_expression needs to return a non-constant, deterministic integer. It is evaluated for each insert and update, so overly complex expressions can lead to performance issues. A hashing function operating on a single column, and where the value changes consistently with the column value, allows for easy pruning on ranges of partitions, and is usually a better choice. For this reason, using multiple columns in a hashing expression is not usually recommended.

LINEAR HASH Partitioning Type

Explore LINEAR HASH partitioning, a variation of HASH that uses a powers-of-two algorithm for faster partition management at the cost of distribution.

Syntax

PARTITION BY LINEAR HASH (partitioning_expression)
[PARTITIONS(number_of_partitions)]

Description

LINEAR HASH partitioning is a form of partitioning, similar to HASH partitioning, in which the server takes care of the partition in which to place the data, ensuring a relatively even distribution among the partitions.

LINEAR HASH partitioning makes use of a powers-of-two algorithm, while HASH partitioning uses the modulus of the hashing function's value. Adding, dropping, merging and splitting partitions is much faster than with the HASH partitioning type, however, data is less likely to be evenly distributed over the partitions.

Example

CREATE OR REPLACE TABLE t1 (c1 INT, c2 DATETIME) 
  PARTITION BY LINEAR HASH(TO_DAYS(c2)) 
  PARTITIONS 5;

This page is licensed: CC BY-SA / Gnu FDL

LINEAR KEY Partitioning Type

Learn about LINEAR KEY partitioning, which combines the internal key hashing with a linear algorithm for efficient partition handling.

Syntax

PARTITION BY LINEAR KEY [ALGORITHM={MYSQL51|MYSQL55|BASE31|CRC32C|XXH32|XXH3}]
([column_names])
[PARTITIONS (number_of_partitions)]

For a description of the different ALGORITHM types, see KEY Partitioning.

PARTITION BY LINEAR KEY ([column_names])
[PARTITIONS (number_of_partitions)]

Description

LINEAR KEY partitioning is a form of partitioning, similar to KEY partitioning.

LINEAR KEY partitioning makes use of a powers-of-two algorithm, while KEY partitioning uses modulo arithmetic to determine the partition number.

Adding, dropping, merging and splitting partitions is much faster than with the ; however, data is less likely to be evenly distributed over the partitions.

This page is licensed: CC BY-SA / Gnu FDL

LIST Partitioning Type

Understand LIST partitioning, where rows are assigned to partitions based on whether a column value matches one in a defined list of values.

LIST partitioning is conceptually similar to RANGE partitioning. In both cases you decide a partitioning expression (a column, or a slightly more complex calculation) and use it to determine which partitions will contain each row. However, with the RANGE type, partitioning is done by assigning a range of values to each partition. With the LIST type, we assign a set of values to each partition. This is usually preferred if the partitioning expression can return a limited set of values.

A variant of this partitioning method, LIST COLUMNS, allows us to use multiple columns and more datatypes.

Syntax

The last part of a CREATE TABLE statement can be the definition of the new table's partitions. In the case of LIST partitioning, the syntax is as follows:

PARTITION BY LIST (partitioning_expression)
(
	PARTITION partition_name VALUES IN (value_list),
	[ PARTITION partition_name VALUES IN (value_list), ... ]
        [ PARTITION partition_name DEFAULT ]
)

PARTITION BY LIST indicates that the partitioning type is LIST.

The partitioning_expression is an SQL expression that returns a value from each row. In the simplest cases, it is a column name. This value is used to determine which partition should contain a row.

partition_name is the name of a partition.

value_list is a list of values. If partitioning_expression returns one of these values, the row are stored in this partition. If we try to insert something that does not belong to any of these value lists, the row are rejected with an error.

The DEFAULT partition catches all records which do not fit into other partitions.

LIST partitioning can be useful when we have a column that can only contain a limited set of values. Even in that case, RANGE partitioning could be used instead; but LIST partitioning allows us to equally distribute the rows by assigning a proper set of values to each partition.

This page is licensed: CC BY-SA / Gnu FDL

RANGE COLUMNS and LIST COLUMNS Partitioning Types

Discover these variants that allow partitioning based on multiple columns and non-integer types, offering greater flexibility than standard RANGE/LIST.

RANGE COLUMNS and LIST COLUMNS are variants of, respectively, and . With these partitioning types, there is not a single partitioning expression; instead, a list of one or more columns is accepted. The following rules apply:

  • The list can contain one or more columns.

  • Columns can be of any

Partitioning Limitations

This page outlines constraints when using partitioning, such as the maximum number of partitions and restrictions on foreign keys and query cache usage.

The following limitations apply to partitioning in MariaDB:

  • Each table can contain a maximum of 8192 partitions.

  • Queries are never parallelized, even when they involve multiple partitions.

  • A table can only be partitioned if the storage engine supports partitioning.

  • All partitions must use the same storage engine. For a workaround, see .

  • A partitioned table cannot contain, or be referenced by, .

  • The is not aware of partitioning and partition pruning. Modifying a partition will invalidate the entries related to the whole table.

  • Updates can run more slowly when and a partitioned table is updated than an equivalent update of a non-partitioned table.

  • All columns used in the partitioning expression for a partitioned table must be part of every unique key that the table may have.

  • In versions prior to , it is not possible to create partitions on tables that contain .

  • contains information about existing partitions.

  • for suggestions on using partitions

This page is licensed: CC BY-SA / Gnu FDL

Partitions Files

Learn how MariaDB stores partitioned tables on the filesystem, typically creating separate .ibd files for each partition when using InnoDB.

A partitioned table is stored in multiple files. By default, these files are stored in the MariaDB (or InnoDB) data directory. It is possible to keep them in different paths by specifying DATA_DIRECTORY and INDEX_DIRECTORY table options. This is useful to store different partitions on different devices.

Note that, if the innodb_file_per_table server system variable is set to 0 at the time of the table creation, all partitions are stored in the system tablespace.

The following files exist for each partitioned tables:

File name
Notes

For example, an InnoDB table with 4 partitions will have the following files:

If we convert the table to MyISAM, we will have these files:

This page is licensed: CC BY-SA / Gnu FDL

Partitions Metadata

Understand how to retrieve metadata about partitions using the INFORMATION_SCHEMA.PARTITIONS table to monitor row counts and storage usage.

The PARTITIONS table in the INFORMATION_SCHEMA database contains information about partitions.

The SHOW TABLE STATUS statement contains a Create_options column, that contains the string 'partitioned' for partitioned tables.

The SHOW CREATE TABLE statement returns the CREATE TABLE statement that can be used to re-create a table, including the partitions definition.

This page is licensed: CC BY-SA / Gnu FDL

ALTER PROCEDURE

The ALTER PROCEDURE statement modifies the characteristics of an existing stored procedure, such as its security context or comment, without changing its logic.

Syntax

ALTER PROCEDURE proc_name [characteristic ...]

characteristic:
    { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'

Description

This statement can be used to change the characteristics of a stored procedure. More than one change may be specified in an ALTER PROCEDURE statement. However, you cannot change the parameters or body of a stored procedure using this statement. To make such changes, you must drop and re-create the procedure using CREATE OR REPLACE PROCEDURE.

You must have the ALTER ROUTINE privilege for the procedure. By default, that privilege is granted automatically to the procedure creator. See Stored Routine Privileges.

Example

ALTER PROCEDURE simpleproc SQL SECURITY INVOKER;

See Also

  • Stored Procedure Overview

This page is licensed: GPLv2, originally from

DROP PROCEDURE

The DROP PROCEDURE statement permanently removes a stored procedure and its associated privileges from the database.

This statement is used to drop a . That is, the specified routine is removed from the server along with all privileges specific to the . You must have the ALTER ROUTINE privilege for the routine. If the server system variable is set, that privilege and EXECUTE are granted automatically to the routine creator - see .

The IF EXISTS clause is a MySQL/MariaDB extension. It prevents an error from occurring if the procedure or function does not exist. ANOTE is produced that can be viewed with .

While this statement takes effect immediately, threads which are executing a procedure can continue execution.

DROP FUNCTION

The DROP FUNCTION statement removes a stored function from the database, deleting its definition and associated privileges.

The DROP FUNCTION statement is used to drop a or a user-defined function (UDF). That is, the specified routine is removed from the server, along with all privileges specific to the function. You must have the ALTER ROUTINE for the routine in order to drop it. If the server system variable is set, both the ALTER ROUTINE and EXECUTE privileges are granted automatically to the routine creator - see .

The IF EXISTS clause is a MySQL/MariaDB extension. It prevents an error from occurring if the function does not exist. ANOTE is produced that can be viewed with

Stored Function Limitations

This page details the restrictions on stored functions, such as the inability to return result sets or use transaction control statements.

The following restrictions apply to stored functions.

  • All of the restrictions listed in Stored Routine Limitations.

  • Any statements that return a result set are not permitted. For example, a regular SELECTs is not permitted, but a SELECT INTO is. A cursor and FETCH statement is permitted.

  • statements are not permitted.

  • Statements that perform explicit or implicit commits or rollbacks are not permitted.

  • Cannot be used recursively.

  • Cannot make changes to a table that is already in use (reading or writing) by the statement invoking the stored function.

  • Cannot refer to a temporary table multiple times under different aliases, even in different statements.

  • ROLLBACK TO SAVEPOINT and RELEASE SAVEPOINT statement which are in a stored function cannot refer to a savepoint which has been defined out of the current function.

  • Prepared statements (, , ) cannot be used, and therefore nor can statements be constructed as strings and then executed.

This page is licensed: CC BY-SA / Gnu FDL

Stored Routine Limitations

Stored routines have specific restrictions, such as prohibiting certain SQL statements (e.g., LOAD DATA) and disallowing result sets in functions.

The following SQL statements are not permitted inside any (, , or ).

  • ; you can use instead.

  • and .

ARIA

Learn about the Aria storage engine in MariaDB Server. Understand its features, advantages, and use cases, particularly for crash-safe operations and transactional workloads.

Aria Storage Engine

An overview of Aria, a storage engine designed as a crash-safe alternative to MyISAM, featuring transactional capabilities and improved caching.

Aria Group Commit

Learn about Aria's group commit functionality, which improves performance by batching commit operations to the transaction log.

A list of status variables specific to the Aria engine, providing metrics on page cache usage, transaction log syncs, and other internal operations.

Understand the different row formats supported by Aria, particularly the default PAGE format which enables crash safety and better concurrency.

A comprehensive list of system variables for configuring Aria, including buffer sizes, log settings, and recovery options.

Explains Aria's deadlock detection mechanism, which uses a two-step process with configurable search depths and timeouts to resolve conflicts.

Frequently asked questions about the Aria storage engine, covering its history, comparison with MyISAM, and key features like crash safety.

A brief history of the naming of the Aria storage engine, explaining its origins as "Maria" and the reasons for the eventual name change.

Aria Group Commit

Learn about Aria's group commit functionality, which improves performance by batching commit operations to the transaction log.

The includes a feature to group commits to speed up concurrent threads doing many inserts into the same or different Aria tables.

By default, group commit for Aria is turned off. It is controlled by the and system variables.

Information on setting server variables can be found on the page.

  • A commit is flush of logs followed by a sync.

WHITE PAPER

The Ultimate Guide to High Availability with MariaDB

Download Now

Tables
Partitioning Tables
Stored Routines
Storage Engines
Triggers & Events
User-Defined Functions
Views
Aria Status Variables
Aria Storage Formats
Aria System Variables
Aria Two-step Deadlock Detection
Aria FAQ
The Aria Name

Creating & Using Views

Quickstart Guides
Altering Tables
Getting Started with Indexes

See Also

mariadb-backup does not support the innodb_log_archive=ON log format and fails when the server is running with innodb_log_archive=ON. Use the InnoDB log archiving PITR procedure instead in that configuration.

as explained here
Point-In-Time Recovery (InnoDB log archiving)

A good way of dealing with canary testing with MariaDB is to use replication, which works even in cases with schemas that are different, to an extent, if statement-based replication (SBR) is used. Using this, a new version is built on one server and a new schema is installed there. This is then set to replicate from the current production system. This is not likely to work for all cases, but in many cases, this is a useful tool to allow for canary testing.

Hidden or invisible columns in MariaDB are a feature that allows a column to exist in a table without being exposed by default, for instance a SELECT * or an INSERT without column names will not touch this column. If the advice given in the previous sections of the document is followed, then this should not be necessary much, but in some cases, it is still a useful feature.

For example, in the example above with the orders_t table, if it is the case that the current application actually does INSERT without specifying the columns to insert into, then a new column, say customer_id, cannot be added. We can then use an invisible column to support this application, including a new version that does use column names in the INSERT and also use the customer_id column:

  • Database

  • Views

  • Replication

  • Invisible columns

Database Naming

Views

Replication

Invisible Columns

See Also

cat /data/backups/full/mariadb_backup_binlog_info

mariadb-node4.00001     321
[mysqld]
datadir=/var/lib/mysql_new
systemctl start mariadb
$ mysqlbinlog --start-position=321 \
      --stop-datetime="2019-06-28 12:00:00" \
      /var/lib/mysql/mariadb-node4.00001 \
      > mariadb-binlog.sql
$ mariadb < mariadb-binlog.sql
MariaDB> USE prod_v2;
MariaDB> CREATE VIEW `orders_t` AS
  SELECT `order_id`, `order_date` FROM `prod_v1`.`orders_t`;
MariaDB> USE prod_v2;
MariaDB> CREATE TABLE `orders_t`(
  `order_id` INTEGER NOT NULL PRIMARY KEY,
  `order_date` DATETIME NOT NULL,
  `customer_id` INTEGER NOT NULL DEFAULT 0);
MariaDB> INSERT INTO `orders_t` SELECT `order_id`, `order_date`
  FROM `prod_v1`.`orders_t`;

MariaDB> USE prod_v1;
MariaDB> RENAME TABLE `orders_t` TO `orders_t_v1`;
MariaDB> CREATE VIEW `orders_t` AS
  SELECT `order_id`, `order_date` FROM `prod_v2`.`orders_t`;
MariaDB> USE prod_v1

MariaDB> ALTER TABLE `orders_t`
  ADD `customer_id` INTEGER NOT NULL DEFAULT 0 INVISIBLE;
MariaDB> SELECT * FROM `orders_t`;
+----------+---------------------+
| order_id | order_date          |
+----------+---------------------+
|        1 | 2024-05-17 18:01:01 |
|        2 | 2025-12-12 18:44:08 |
+----------+---------------------+
2 rows in set (0.004 sec)

MariaDB> INSERT INTO `orders_t`
  (`order_id`, `order_date`, `customer_id`) VALUES(3, NOW(), 2);

For Debian/Ubuntu:Bash

sudo apt update
  • For Red Hat/CentOS/Fedora:Bash

    sudo yum update # For older systems
    sudo dnf update # For newer systems
  • Install MariaDB Server:

    Install the MariaDB server and client packages.

    • For Debian/Ubuntu:Bash

      sudo apt install mariadb-server mariadb-client galera-4
    • For Red Hat/CentOS/Fedora:Bash

      sudo dnf install mariadb mariadb-server
  • Secure the Installation:

    After installation, run the security script to set a root password, remove anonymous users, and disable remote root login.

    sudo mariadb-secure-installation

    Follow the prompts to configure your security settings.

  • Start and Verify the Service:

    MariaDB typically starts automatically after installation. You can check its status and manually start it if needed.

    • Check status:

      sudo systemctl status mariadb
    • Start service (if not running):Bash

      sudo systemctl start mariadb
    • Verify installation by connecting as root:Bash

      Enter the root password you set during the secure installation.

  • For Windows, MariaDB provides an .msi installer for a straightforward graphical installation.

    Steps:

    1. Download MariaDB:

      Visit the MariaDB downloads page to get the latest .msi installer.

    2. Run the Installer:

      Double-click the downloaded .msi file to start the installation wizard.

    3. Follow On-Screen Instructions:

      The installer will guide you through the process, including:

      • Accepting the end-user license agreement.

      • Selecting features and the installation directory.

      • Setting a password for the

    • Firewall: Ensure your firewall is configured to allow connections to MariaDB on the appropriate port (default 3306) if you need remote access.

    • Root Password: Always set a strong root password during the secure installation step.

    • Further Configuration: For production environments, you may need to adjust further settings in the MariaDB configuration files (e.g., my.cnf on Linux).

    • Get Started with MariaDB

    • How To Install MariaDB on Ubuntu 22.04 - DigitalOcean

    • Install MariaDB - MariaDBTutorial.com

    For Linux (Ubuntu/Debian/Red Hat-based distributions)

    For Windows

    Important Notes:

    Additional Resources:

  • Replace your_username with your MariaDB username and /path/to/your/backupfile.sql with the actual path to your dump file.

  • You will be prompted for the password for your_username.

  • The < symbol is a standard input (STDIN) redirect, feeding the contents of backupfile.sql to the mariadb client.

  • Often, the dump file itself contains CREATE DATABASE IF NOT EXISTS and USE database_name; statements, so a specific database doesn't always need to be named on the command line during restore. If your dump file restores to a specific database, ensure that user has permissions to it. If the dump file does not specify a database, you might need to create the database first and then run:

    • Data Overwriting: Restoring a dump file will execute the SQL statements within it. If the dump file contains DROP TABLE and CREATE TABLE statements (common for full backups), existing tables with the same names will be dropped and recreated, leading to loss of any data added or changed since the backup was made.

    • Backup Age: If your dump file is several days old, restoring it entirely could revert all data in the affected tables/databases to that older state. This can be disastrous if only a small portion of data was lost and the rest has been actively updated.

    Always ensure you understand the contents of the dump file and the potential impact before initiating a restore, especially on a production system. Consider testing the restore on a non-production environment first if possible.

    If only one table has been lost or corrupted and your backup file contains an entire database (or multiple tables), a full restore might overwrite recent, valid data in other tables. Here’s a method to restore only a specific table using a temporary user with restricted privileges:

    1. Create a Temporary User: Create a MariaDB user specifically for this restore operation.

    2. Grant Limited Privileges:

      • Grant this temporary user the minimal privileges needed for the dump file to execute up to the point of restoring your target table. This might be SELECT on all tables in the database if the dump file checks other tables, or simply the ability to USE the database.

      • Then, grant ALL PRIVILEGES (or specific necessary privileges like CREATE, DROP, INSERT, SELECT) only on the specific table you want to restore.

      Example SQL to create a temporary user and grant permissions (replace placeholders):

    3. Restore Using the Temporary User and --force:

      Use the mariadb client with the temporary user and the --force option. The --force option tells MariaDB to continue executing statements in the dump file even if some SQL errors occur. Errors will occur for operations on tables where admin_restore_temp lacks permissions, but operations on table_to_restore (where permissions were granted) should succeed.

      Bash

      You will be prompted for the password of admin_restore_temp.

    4. Verify Restoration: Check that table_to_restore has been correctly restored.

    5. Clean Up: Drop the temporary user once the restoration is confirmed:

    This method helps to isolate the restore operation to the intended table, protecting other data from being inadvertently reverted to an older state.

    mariadb --user your_username --password < /path/to/your/backupfile.sql

    Basic Restoration Process

    Important Considerations Before Restoring

    Restoring a Single Table Selectively

    Full Backup and Restore (mariadb-backup)

    Learn how to perform and restore full physical backups of MariaDB databases using the mariadb-backup tool, ensuring consistent data recovery.

    Incremental Backup and Restore (mariadb-backup)

    This guide explains how to create and apply incremental backups with mariadb-backup, saving storage space and reducing backup time.

    Point-In-Time Recovery (PITR, mariadb-backup)

    Explains how to restore (recover) to a specific point in time. Point-in-time recovery is often referred to as PITR.

    Partial Backup and Restore (mariadb-backup)

    Back up specific databases or tables. This guide explains how to filter your backup to include only the data you need.

    Restoring Individual Databases From a Full Backup (mariadb-backup)

    Restore a single database from a full backup. Learn the procedure to extract and recover a specific database schema from a larger backup set.

    Restoring Individual Tables and Partitions (mariadb-backup)

    Restore specific tables from a backup. Learn the process of importing individual .ibd files to recover specific tables without restoring the whole database.

    Setting up a Replica (mariadb-backup)

    Initialize a replication slave using a backup. This guide shows how to use mariadb-backup to provision a new replica from a master server.

    Files Backed Up by mariadb-backup

    List of file types included in a backup. Understand which data files, logs, and configuration files are preserved during the backup process.

    Files Created by mariadb-backup

    Reference of files generated during backup. This page explains the purpose of metadata files created by the mariadb-backup.

    Using Encryption and Compression Tools With mariadb-backup

    Secure and compress backup streams. Learn to pipe backup output to tools like GPG and GZIP for encryption and storage efficiency.

    How mariadb-backup Works

    Deep dive into backup mechanics. Understand how the tool handles redo logs, locking, and file copying to ensure consistent backups.

    mariadb-backup and BACKUP STAGE

    Understand backup locking stages. This page explains how mariadb-backup uses BACKUP STAGE statements to minimize locking during operation.

    Configure State Snapshot Transfers for Galera Cluster. Learn to use mariadb-backup for non-blocking data transfer when a new node joins a cluster.

    Perform a manual node provision. This guide details the steps to manually backup a donor and restore it to a joiner node in a Galera Cluster.

    mariadb-backup Overview
    mariadb-backup Options
    ,
    ,
    , and
    types.
  • Only bare columns are permitted; no expressions.

  • All the specified columns are compared to the specified values to determine which partition should contain a specific row. See below for details.

    The last part of a CREATE TABLE statement can be definition of the new table's partitions. In the case of RANGE COLUMNS partitioning, the syntax is as follows:

    The syntax for LIST COLUMNS is as follows:

    partition_name is the name of a partition.

    To determine which partition should contain a row, all specified columns are compared to each partition definition.

    With LIST COLUMNS, a row matches a partition if all row values are identical to the specified values. At most one partition can match the row.

    With RANGE COLUMNS, a row matches a partition if it is less than the specified value tuple in lexicographic order. The first partition that matches the row values are used.

    The DEFAULT partition catches all records which do not fit in other partitions. Only one DEFAULT partition is allowed.

    RANGE COLUMNS partition:

    LIST COLUMNS partition:

    This page is licensed: CC BY-SA / Gnu FDL

    RANGE
    LIST
    PARTITION BY RANGE COLUMNS (col1, col2, ...)
    (
    	PARTITION partition_name VALUES LESS THAN (value1, value2, ...),
    	[ PARTITION partition_name VALUES LESS THAN (value1, value2, ...), ... ]
    )
    PARTITION BY LIST COLUMNS (partitioning_expression)
    (
    	PARTITION partition_name VALUES IN (value1, value2, ...),
    	[ PARTITION partition_name VALUES IN (value1, value2, ...), ... ]
            [ PARTITION partititon_name DEFAULT ]
    )
    CREATE OR REPLACE TABLE t1 (
      date1 DATE NOT NULL,
      date2 DATE NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE COLUMNS (date1,date2) (
        PARTITION p0 VALUES LESS THAN ('2013-01-01', '1994-12-01'),
        PARTITION p1 VALUES LESS THAN ('2014-01-01', '1995-12-01'),
        PARTITION p2 VALUES LESS THAN ('2015-01-01', '1996-12-01')
    );
    CREATE OR REPLACE TABLE t1 (
      num TINYINT(1) NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY LIST COLUMNS (num) (
        PARTITION p0 VALUES IN (0,1),
        PARTITION p1 VALUES IN (2,3),
        PARTITION p2 DEFAULT
      );

    Syntax

    Comparisons

    Examples

    integer
    string
    DATE
    DATETIME
    .

    For dropping a user-defined functions (UDF), see DROP FUNCTION UDF.

    • DROP PROCEDURE

    • Stored Function Overview

    • CREATE FUNCTION

    • CREATE FUNCTION UDF

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    DROP FUNCTION [IF EXISTS] f_name

    Syntax

    Description

    IF EXISTS

    stored function
    privilege
    automatic_sp_privileges
    Stored Routine Privileges
    SHOW WARNINGS
    DROP FUNCTION hello;
    Query OK, 0 rows affected (0.042 sec)
    
    DROP FUNCTION hello;
    ERROR 1305 (42000): FUNCTION test.hello does not exist
    
    DROP FUNCTION IF EXISTS hello;
    Query OK, 0 rows affected, 1 warning (0.000 sec)
    
    SHOW WARNINGS;
    +-------+------+------------------------------------+
    | Level | Code | Message                            |
    +-------+------+------------------------------------+
    | Note  | 1305 | FUNCTION test.hello does not exist |
    +-------+------+------------------------------------+

    Examples

    See Also

  • number_of_partitions is a positive integer specifying the number of partitions into which to divide the table. If the PARTITIONS clause is omitted, the default number of partitions is one.

  • To determine which partition to use, perform the following calculation:

    For example, if the expression is TO_DAYS(datetime_column) and the number of partitions is 5, inserting a datetime value of '2023-11-15' would determine the partition as follows:

    • TO_DAYS('2023-11-15') gives a value of 739204.

    • MOD(739204,5) returns 4, so the 4th partition is used.

    HASH partitioning makes use of the modulus of the hashing function's value. The LINEAR HASH partitioning type is similar, using a powers-of-two algorithm. Data is more likely to be evenly distributed over the partitions than with the LINEAR HASH partitioning type; however, adding, dropping, merging and splitting partitions is much slower.

    Using the Information Schema PARTITIONS Table for more information:

    • Partition Maintenance for suggestions on using partitions

    This page is licensed: CC BY-SA / Gnu FDL

    PARTITION BY HASH (partitioning_expression)
    [PARTITIONS(number_of_partitions)]

    Syntax

    Description

    partitioning
    MOD(partitioning_expression, number_of_partitions)
    CREATE OR REPLACE TABLE t1 (c1 INT, c2 DATETIME) 
      PARTITION BY HASH(TO_DAYS(c2)) 
      PARTITIONS 5;
    INSERT INTO t1 VALUES (1,'2023-11-15');
    
    SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS 
      WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
    +----------------+------------+
    | PARTITION_NAME | TABLE_ROWS |
    +----------------+------------+
    | p0             |          0 |
    | p1             |          0 |
    | p2             |          0 |
    | p3             |          0 |
    | p4             |          1 |
    +----------------+------------+

    Determining the Partition

    Examples

    See Also

    sent to disk means written to disk but not sync()ed,

  • flushed mean sent to disk and synced().

  • LSN means log serial number. It's refers to the position in the transaction log.

  • The thread which first started the commit is performing the actual flush of logs. Other threads set the new goal (LSN) of the next pass (if it is maximum) and wait for the pass end or just wait for the pass end.

    The effect of this is that a flush (write of logs + sync) will save all data for all threads/transactions that have been waiting since the last flush.

    The first thread sends all changed buffers to disk. This is repeated as long as there are new LSNs added. The process can not loop forever because we have a limited number of threads and they will wait for the data to be synced.

    Pseudo code:

    If less than rate microseconds has passed since the last sync, then after buffers have been sent to disk, wait until rate microseconds has passed since last sync, do sync and return. This ensures that if we call sync infrequently we don't do any waits.

    Note that soft group commit should only be used if you can afford to lose a few rows if your machine shuts down hard (as in the case of a power failure).

    Works like in non group commit' but the thread doesn't do any real sync(). If aria_group_commit_interval is not zero, the sync() calls are performed by a service thread with the given rate when needed (new LSN appears). If aria_group_commit_interval is zero, there are no sync() calls.

    The code for this can be found in storage/maria/ma_loghandler.c::translog_flush().

    This page is licensed: CC BY-SA / Gnu FDL

    Terminology

    Aria storage engine
    aria_group_commit
    aria_group_commit_interval
    Server System Variables
    do
       send changed buffers to disk
     while new_goal
    sync

    Non Group commit logic (aria_group_commit="none")

    If hard group commit is enabled (aria_group_commit="hard")

    If hard commit and aria_group_commit_interval=0

    If hard commit and aria_group_commit_interval > 0

    If soft group commit is enabled (aria_group_commit="soft")

    Code

    CHANGE MASTER TO

  • INSERT DELAYED is permitted, but the statement is handled as a regular INSERT.

  • LOCK TABLES and UNLOCK TABLES.

  • References to local variables within prepared statements inside a stored routine (use user-defined variables instead).

  • BEGIN (WORK) is treated as the beginning of a BEGIN END block, not a transaction, so START TRANSACTION needs to be used instead.

  • The number of permitted recursive calls is limited to max_sp_recursion_depth. If this variable is 0 (default), recursivity is disabled. The limit does not apply to stored functions.

  • Most statements that are not permitted in prepared statements are not permitted in stored programs. See Prepare Statement:Permitted statements for a list of statements that can be used. SIGNAL, RESIGNAL and GET DIAGNOSTICS are exceptions, and may be used in stored routines.

  • There are also further limitations specific to the kind of stored routine.

    Note that, if a stored program calls another stored program, the latter will inherit the caller's limitations. So, for example, if a stored procedure is called by a stored function, that stored procedure will not be able to produce a result set, because stored functions can't do this.

    • Stored Function Limitations

    • Trigger Limitations

    • Event Limitations

    This page is licensed: CC BY-SA / Gnu FDL

    stored routines
    stored functions
    stored procedures
    events
    triggers
    ALTER VIEW
    CREATE OR REPLACE VIEW
    LOAD DATA
    LOAD TABLE

    See Also

    IF EXISTS:
    • DROP FUNCTION

    • Stored Procedure Overview

    • CREATE PROCEDURE

    • ALTER PROCEDURE

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    DROP PROCEDURE [IF EXISTS] sp_name
    DROP PROCEDURE simpleproc;

    Syntax

    Description

    Examples

    stored procedure
    procedure
    automatic_sp_privileges
    Stored Routine Privileges
    SHOW WARNINGS
    DROP PROCEDURE simpleproc;
    ERROR 1305 (42000): PROCEDURE test.simpleproc does not exist
    
    DROP PROCEDURE IF EXISTS simpleproc;
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    SHOW WARNINGS;
    +-------+------+------------------------------------------+
    | Level | Code | Message                                  |
    +-------+------+------------------------------------------+
    | Note  | 1305 | PROCEDURE test.simpleproc does not exist |
    +-------+------+------------------------------------------+

    See Also

    +-----------+----+
    | Last_Name | ID |
    +-----------+----+
    | Crowne    |  4 |
    | Crowne    |  5 |
    | Foster    |  2 |
    | Marx      |  3 |
    | Mond      |  1 |
    | Watson    |  6 |
    +-----------+----+
    +-------------------------+----+
    | Position                | ID |
    +-------------------------+----+
    | Cashier                 |  3 |
    | Cashier                 |  4 |
    | Chief Executive Officer |  1 |
    | Janitor                 |  6 |
    | Restocker               |  5 |
    | Store Manager           |  2 |
    +-------------------------+----+
    CREATE INDEX
    Getting Started with Indexes
    $ mariadb-backup --prepare --export \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword

    Restoring the Backup

    Restoring Individual Non-Partitioned Tables

    Restoring Individual Partitions and Partitioned Tables

    MDEV-13466
    Importing Transportable Tablespaces for Partitioned Tables
    see this page
    see this page
    mariadb-backup --user=root --backup --stream=xbstream | gzip | openssl  enc -aes-256-cbc -k mypass > backup.xb.gz.enc
    openssl  enc -d -aes-256-cbc -k mypass -in backup.xb.gz.enc |gzip -d| mbstream -x
    mariadb-backup --user=root --backup --stream=xbstream | 7z a -si backup.xb.7z
    7z e backup.xb.7z -so |mbstream -x
    mariadb-backup --user=root --backup --stream=xbstream  | zstd - -o backup.xb.zst -f -1
    zstd -d backup.xbstream.zst -c | mbstream -x
    mariadb-backup --user=root --backup --stream=xbstream | gpg -c --passphrase SECRET --batch --yes -o backup.xb.gpg
    gpg --decrypt --passphrase SECRET --batch --yes  backup.xb.gpg | mbstream -x

    Compressing and Encrypting with 7Zip

    Compressing with zstd

    Encrypting With GPG

    Interactive Input for Passphrases

    Writing extra status files

    see this page
    see this page
    CREATE OR REPLACE TABLE t1 (
      num TINYINT(1) NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY LIST (num) (
        PARTITION p0 VALUES IN (0,1),
        PARTITION p1 VALUES IN (2,3),
        PARTITION p2 DEFAULT
      );

    Use Cases

    Example

    table_name.frm

    Contains the table definition. Non-partitioned tables have this file, too.

    table_name.par

    Contains the partitions definitions.

    table_name#P#partition_name.ext

    Normal files created by the storage engine use this pattern for names. The extension depends on the storage engine.

    orders.frm
    orders.par
    orders#P#p0.ibd
    orders#P#p1.ibd
    orders#P#p2.ibd
    orders#P#p3.ibd
    orders.frm
    orders.par
    orders#P#p0.MYD
    orders#P#p0.MYI
    orders#P#p1.MYD
    orders#P#p1.MYI
    orders#P#p2.MYD
    orders#P#p2.MYI
    orders#P#p3.MYD
    orders#P#p3.MYI
    CREATE OR REPLACE TABLE t1 (v1 INT)
      PARTITION BY LINEAR KEY (v1)
      PARTITIONS 2;

    Example

    KEY partitioning type

    See Also

    LIST
    RANGE COLUMNS and LIST COLUMNS
    HASH
    LINEAR HASH
    KEY
    LINEAR KEY
    SYSTEM_TIME
    Partitioning Overview

    See Also

    Using CONNECT - Partitioning and Sharding
    foreign keys
    query cache
    binlog_format=ROW
    GEOMETRY types
    INFORMATION_SCHEMA.PARTITIONS
    Partition Maintenance
    REPLACE
    FLUSH
    PREPARE
    EXECUTE
    DEALLOCATE PREPARE
    CREATE PROCEDURE
    SHOW CREATE PROCEDURE
    DROP PROCEDURE
    SHOW CREATE PROCEDURE
    SHOW PROCEDURE STATUS
    Stored Routine Privileges
    Information Schema ROUTINES Table
    fill_help_tables.sql

    Changing Times in MariaDB

    This guide explores MariaDB functions for performing calculations and modifications on date and time values, like DATE_ADD and DATE_SUB.

    This guide explores MariaDB functions for performing calculations and modifications on date and time values. Learn to use functions like DATE_ADD, DATE_SUB, TIME_TO_SEC, and SEC_TO_TIME to accurately add or subtract intervals and manage date/time changes that cross midnight or month/year boundaries.

    (For foundational knowledge on date and time data types and basic retrieval, please refer to the "Date and Time Handling Guide".)

    Calculating Time Across Midnight

    When adding hours to a TIME value, calculations might exceed 24 hours. For example, if a task is entered at 23:00 and is promised 2 hours later, a simple addition can be problematic.

    Consider an INSERT statement for a tickets table with entered and promised TIME columns:

    • TIME_TO_SEC(time) converts a time value to seconds.

    • SEC_TO_TIME(seconds) converts seconds back to a time format (HHH:MM:SS).

    If CURTIME() is 23:00:00 (82,800 seconds), 82800 + 7200 = 90000 seconds. SEC_TO_TIME(90000) would result in 25:00:00. While MariaDB can store this, it doesn't represent a standard clock time for the next day.

    Modulo Arithmetic for Time Rollover:

    To handle time wrapping around the 24-hour clock (86,400 seconds in a day) for TIME columns, use the modulo operator (%):

    If current time is 23:00, (82800 + 7200) % 86400 becomes 90000 % 86400, which is 3600 seconds. SEC_TO_TIME(3600) correctly results in 01:00:00.

    The modulo arithmetic above gives the correct time of day but doesn't indicate if the promised time falls on the next calendar day. For calculations where the date might change, it's essential to use DATETIME (or TIMESTAMP) data types.

    If your table initially used separate DATE and TIME columns (e.g., ticket_date, entered_time, promised_time), you would typically alter the table to use DATETIME columns (e.g., entered_datetime, promised_datetime) to store both date and time information accurately. This often involves:

    1. Adding new DATETIME columns.

    2. Populating them by combining the old date and time columns (e.g., using CONCAT(ticket_date, ' ', entered_time)).

    3. Dropping the old separate date and time columns. (Always back up your data before such structural changes.)

    With DATETIME columns, NOW() can be used to get the current date and time.

    The DATE_ADD(date, INTERVAL expr unit) function is the most robust way to add a duration to a date, time, or datetime value. It correctly handles rollovers across days, months, and years.

    • date: A DATE, DATETIME, or TIME value.

    • expr: The value of the interval to add.

    Adding Hours (handles date change):

    If entered and promised are DATETIME columns:

    If NOW() is 2025-06-03 23:00:00, promised will correctly be 2025-06-04 01:00:00.

    Adding Combined Hours and Minutes:

    Use HOUR_MINUTE as the unit. The expr is a string 'hours:minutes'.

    If NOW() is 2025-06-03 23:00:00, this results in 2025-06-04 01:30:00.

    DATE_ADD also correctly handles date changes across month and year boundaries, including leap years.

    Adding Days:

    If NOW() is 2025-02-27, this would result in 2025-03-04 (assuming 2025 is not a leap year).

    Adding Combined Days and Hours:

    Use DAY_HOUR as the unit. The expr is a string 'days hours'.

    Adding Combined Years and Months:

    Use YEAR_MONTH as the unit. The expr is a string 'years-months'.

    If NOW() is 2025-09-15 23:00:00, this results in 2026-11-15 23:00:00. This type of interval typically does not affect the day or time components directly, only the year and month.

    Using DATE_ADD with a Negative Interval:

    You can subtract durations by providing a negative value for expr.

    Using DATE_SUB(date, INTERVAL expr unit):

    This function is specifically for subtracting durations.

    Note: With DATE_SUB, expr is positive for subtraction. A negative expr would result in addition.

    Making Backups with mariadb-dump Guide

    Create logical backups of MariaDB databases with the mariadb-dump utility, covering how to back up all databases, specific databases, or individual tables.

    This guide explains how to use the mariadb-dump utility to create essential backup (dump) files of your MariaDB data. Learn to effectively back up all databases, specific databases, or individual tables, ensuring your data is protected and can be restored when needed.

    About mariadb-dump

    mariadb-dump is a command-line utility included with MariaDB for creating logical backups of your databases. It was previously known as mysqldump, which often still works as a symbolic link.

    Key Advantages:

    • No Server Shutdown: Backups can be performed while the MariaDB server is running.

    • SQL Output: It generates a .sql file (a "dump file") containing SQL statements (CREATE TABLE, INSERT, etc.) necessary to reconstruct the databases and data.

    All mariadb-dump commands are executed from your system's command-line shell, not within the mariadb client.

    To export all databases managed by your MariaDB server:

    • --user=admin_backup: Specifies the MariaDB user performing the backup (this user needs appropriate privileges, typically at least SELECT and LOCK TABLES).

    • --password: Prompts for the user's password. For use in scripts where prompting is not possible, you can use --password=yourpassword (note the absence of a space and the security implication of having the password in a script or command history).

    Commonly Used Option for Efficiency:

    • --extended-insert (or -e): Creates INSERT statements that include multiple rows per statement. This generally results in a smaller dump file and faster restores. This option is often enabled by default but can be explicitly stated.

    Example with long options and password in script:

    Backing up databases individually can result in smaller, more manageable dump files and allow for more flexible backup schedules.

    • --databases (or -B): Followed by the name of the database to dump.

    • To back up multiple specific databases, list their names separated by spaces after the --databases option:

    For very large databases, or if only certain tables change frequently, you might back up individual tables.

    • First, specify the database name (your_database_name).

    • Then, list one or more table names (table_name1, table_name2) separated by spaces.

    • Note that the --databases

    • User Privileges: The MariaDB user specified with --user needs at least SELECT privileges for the tables being dumped. LOCK TABLES privilege is needed if using --lock-tables. RELOAD or FLUSH_TABLES might be needed for options like --flush-logs or --master-data. For --single-transaction

    This page is licensed: CC BY-SA / Gnu FDL

    Database Applications

    This section offers advice on writing and maintaining applications that use databases, covering schema design, code practices, and testing.

    By Anders Karlsson, Principal Sales Engineer at MariaDB Plc — 24 minutes read

    This document offers guidance on creating and maintaining database applications with minimal downtime and effort, covering aspects from database schema design to application code.

    Here's a summary of key areas and advice covered; find the full guide on the subsequent pages.

    • Database Design: A well-designed database is crucial. Standardization in naming conventions (e.g., orders_t), data types, character sets (preferably UTF-8 for full Unicode support, utf8mb4), and collations is highly recommended to ensure ease of maintenance.

    • Data Types:

      • Choosing appropriate types: Consider if a number will be computed; if not, a string might be better (e.g., VARCHAR for product codes with leading zeros).

      • Text/String: Use VARCHAR and be generous with sizing, as schema upgrades for length extensions are undesirable. UTF-8 (specifically utf8mb4

    • Schema Objects:

      • Views: Excellent for hiding complexity and supporting different schema versions. Naming views with version strings (orders_v_1) can be beneficial. They can also be used to reference data in newer schemas during migration.

    • Application Code:

      • Separation of Concerns: While complete separation of application logic and database logic is difficult, practices like using ORMs and stored procedures can help.

      • Object Relational Mappers (ORM): Tools like Hibernate allow applications to be less reliant on specific database schema details, aiding maintenance, though performance and complex operations might still require attention.

    • Code and Schema Standardization: Adhering to internal standards for data types, column names, and database interaction improves maintainability and code readability.

    • Complex SQL: Break down very complex SQL (especially SELECT JOINs) into multiple statements or use temporary tables to improve readability and maintainability.

    • Canary Testing:

      • Database Naming: Utilize the MariaDB database concept (similar to schema) as a namespace to allow different schemas to coexist, avoiding hard-coding database names.

      • Views: Create separate databases for new versions with views referencing data in older or newer schemas to manage transitions.

    This section provides an introduction to developing database-backed applications with MariaDB, discussing maintenance, upgrades, and separation of concerns.

    Learn about best practices for database schema design, including naming conventions, choosing appropriate data types, and using views to abstract complexity.

    This guide covers application-side considerations, such as using ORMs, stored procedures, and writing robust SQL that handles schema changes gracefully.

    Explore strategies for safely testing schema and application changes using canary deployments, replication, and features like invisible columns.

    Database Design

    Learn about best practices for database schema design, including naming conventions, choosing appropriate data types, and using views to abstract complexity.

    Overview

    The design of the database is a key here; a well-designed database with appropriate relationships, naming, etc., is still a solid foundation to build a structure on, but as things evolve, it will change with the application. The task is to implement necessary changes, but also to consider future enhancements in the design of the database.

    Standardization

    To make a database schema easy to maintain, it is best to adhere to some kind of naming standard. What this standard is has less importance than ensuring that it is adhered to. Some like to prefix a name with the type indicator, some like to suffix it, and others ignore this; whichever is your preference, stick to it.

    CREATE TABLE `orders_t`(`order_id` BIGINT NOT NULL PRIMARY KEY,
       `order_date` DATETIME NOT NULL,
       `customer_id` BIGINT NOT NULL,
       FOREIGN KEY(`customer_id`) REFERENCES `customer_t`(`customer_id`));
    

    In addition, sticking to a standard for data types to use, including character sets and collations, is a good practice.

    Database Data Types

    The data types used really need careful consideration. There are performance aspects here, but in addition, the ease of upgrading the schema should also be considered. Any data type has limitations in and of themselves, and in many cases, limits are introduced as part of a column definition, such as the maximum length of string types and the precision of numeric datatypes.

    Choosing an Appropriate Data Type

    In some cases, a suitable data type is obvious; in other cases, this is not the case. Take, for example, a product code consisting of 8 digits; is it best stored as an INTEGER or as a VARCHAR(8)? The former will be more compact in storage and will be faster, the latter less so. Also, are leading zeros significant? If this is the case, then an INTEGER is likely not a good option. Actually, in general, if you are not computing a number, it is likely better to be stored as a string.

    The most common text data types are variable length, so in general, there is no need to be conservative when sizing a VARCHAR, for example. In MariaDB, there is a limit on the total row size of a table, and in this calculation, the maximum size of VARCHAR is used, so this might be a reason not to extend this too much. In some cases, you know the maximum length of a VARCHAR column, and in that case, it should be used, of course, but be careful, as things might change over time, say some code of some kind might be extended in the future.

    In other situations, you cannot really tell what the maximum might be, say a name, then make sure that there is ample space available, having to upgrade a schema just because you have to extend the size of a VARCHAR column is unnecessary.

    One issue that needs to be considered is what character set to use for text strings. In most cases, it is recommended that UTF-8 be used, but note that MariaDB has a few options here; either you can use 3-byte UTF-8, called utf8mb3, which allows for 2-byte Unicode or 4-byte, called utf8mb4, which allows full Unicode support. When you use UTF-8, though, remember that storage of strings might be longer. MariaDB ensures that space is allocated as appropriate, but the max potential length of a VARCHAR(8) string using utf8mb3 will be 24 bytes, and when it comes to calculating the maximum row size, this is calculated as 24, not 8, bytes.

    Collations determine how a string is sorted, for example, when an ORDER BY is used and when indexes are created. You really do want to avoid upgrading a schema to change the collation of a column in a table, so be careful here.

    It is recommended that you allow as much space as possible when you don’t know the maximum length of a column in a table. It is recommended to use UTF-8 for string data; it does have some drawbacks, but in the end, it is the best general-use character set. It might be useful to use a single-byte character set in some cases, say when using some alphanumeric code item such as a product code, but mostly you are best off with UTF-8 even here, as mixing different data types makes things unnecessarily complicated.

    Similar things can be said for collations; there are few reasons to deviate from using just a single collation for a specific application database from the point of view of creating a schema that can be easily maintained at least. From a performance point of view, there are things to consider when determining which collation to use.

    Numeric data types come in several flavors, from a high level we are looking at integer types, floating point types and fixed-point types. In MariaDB, all numeric types are fixed-size storage. From the point of view of schema maintenance, the first thing to look for when it comes to creating a database schema that will need less maintenance is to ensure that values fit in the types used. BIGINT instead of INTEGER is often a good idea, in particular when used for auto-generated primary keys.

    Another thing to watch out for is FLOAT and DOUBLE, including aliases for these, as they are floating-point, which means there might be rounding issues. Using these types for monetary values might not always be a good idea.

    An alternative to FLOAT and DOUBLE is to use the fixed-point DECIMAL type, which is exact. Note also that in SQL_MODE=Oracle in MariaDB, the Oracle type NUMERIC is an alias for DECIMAL.

    MariaDB has a range of temporal types, from the standard DATETIME and TIMESTAMP to the more specialised DATE, YEAR and TIME. The by far most used ones are DATETIME and TIMESTAMP, and there are some things to consider when it comes to maintenance. DATETIME and TIMESTAMP both store similar values, but there is a difference in that DATETIME stores the time as it is, whereas TIMESTAMP takes the time zone on the client side into effect.

    From a schema maintenance point of view, make sure that you understand how these two types work before using them.

    Most database systems on the market have types that are specific to that system in particular, in MariaDB, which includes ENUM and SET types. Some types are little used, like BIT and smaller variations of INTEGER types. As for ENUM and SET, these have some useful attributes in that they, on the one hand, require limited storage, but to extend them with additional values, the schema has to be altered, which might be an issue in many cases.

    Beyond this, there are other objects to handle when it comes to schema and application maintenance. Here, we will look at some of them from the point of view of creating a schema that allows itself to be maintained with limited effort.

    Using views has several advantages, and although using views might have performance issues, they provide many advantages when it comes to maintaining a database schema. When considering that, this assumes that the views are created with performance and maintenance in mind.

    Very complex queries that might need to be maintained can well be put in views. It may also be advantageous to use views to support different versions of a schema over time; adding a version string to VIEW names might well be a good idea.

    Forming a Backup Strategy

    Learn how to design a robust backup strategy tailored to your business needs, balancing recovery time objectives and data retention policies.

    Overview

    The strategy applied when implementing data backups depends on business needs.

    Data backup strategy depends on business needs. Business needs can be evaluated by performing a data inventory, determining data recovery objectives, considering the replication environment, and considering encryption requirements. Also critical is a backup storage strategy and testing backup and recovery procedures.

    Data Inventory

    Backup strategy requirements flow from the understanding you build by performing a data inventory. A data inventory is established by asking questions such as:

    1. What data is housed in the databases?

    2. What business purpose does this data serve?

    3. How long does the data needed to be retained in order to meet this business purpose?

    4. Are there any legal or regulatory requirements, which would limit the length of data retention?

    Data recovery requirements are often defined in terms of Recovery Point Objective (RPO) and Recovery Time Objective (RTO). RTO and RPO are considered in the context of the data identified in the .

    Recovery Point Objective (RPO) defines the maximum amount of data a business is willing to lose. For example, a business can define a RPO of 24 hours.

    Recovery Time Objective (RTO) defines how quickly a business needs to restore service in the event of a fault. For example, a business can define a RTO of 8 hours.

    Backup strategy plays a substantial role in achieving RPO and RTO.

    RPO depends on completion of backups, which provide a viable recovery point. Since RPO is measured at backup completion, not backup initiation, backup jobs must be scheduled at an interval smaller than the RPO.

    Techniques for achieving RPO include:

    • Frequent incremental backups and less frequent full backups.

    • Performing backups in conjunction with replication and clustering to eliminate impact on production workloads, allowing a higher backup frequency.

    • Automated monitoring of backup status.

    The RTO window typically commences at the point when a decision is made by the business to recover from backups, not at the start of an incident.

    Techniques for achieving RTO include:

    • Leveraging information produced during incident response, which can reduce the set of data to restore from backups, or identify specific data validation requirements dependent on the nature of the incident.

    • Having fast access to backup data. Performance requirements of backup infrastructure should be understood for both backup and restoration workloads.

    • Using delayed replication, either within the same data center or to a different data center, can provide shorter path to recovery. This is particularly true when coupled with robust application monitoring, which allows intervention before the window of delay elapses.

    MariaDB Enterprise Server supports several implementations of replication, which accurately duplicates data from one Server to one or more other Servers. The use of a dedicated replica as a source for backups can minimize workload impact.

    MariaDB Enterprise Cluster implements virtually synchronous replication, where each Server instance contains a replica of all of the data for the Cluster. Backups can be performed from any node in the Cluster.

    MariaDB Enterprise Server supports encryption on disk (data-at-rest encryption) and on the network (data-in-transit encryption).

    MariaDB Enterprise Backup copies tablespaces from disk. When data-at-rest encryption is enabled, backups contain encrypted data.

    MariaDB Enterprise Backup supports TLS encryption for communications with MariaDB Enterprise Server. To enable TLS encryption, set TLS options from the command-line or in the configuration file:

    How backups are stored can impact backup viability. Backup storage also presents separate risks. These risks need to be carefully considered:

    • Backup data should always be stored separately from the system being backed up, and separate from the system used for recovery.

    • Backup data should be subject to equal or more controls than data in production databases. For example, backup data should generally be encrypted even where a decision has bee made that a production database will not use data-at-rest encryption.

    • Business requirements may define a need for offsite storage of backups as a means of guaranteeing delivery on RPO. In these cases you should also consider onsite storage of backups as a means of guaranteeing delivery on RTO.

    Testing has been identified as a critical success factor for the successful operation of data systems.

    Backups should be tested. Recovery using backups and recovery procedures should be tested.

    This page is: Copyright © 2025 MariaDB. All rights reserved.

    Backup Optimization

    Discover techniques to optimize your backup processes, including multithreading, incremental backups, and leveraging storage snapshots.

    Overview

    Backup and restore implementations can help overcome specific technical challenges that would otherwise pose a barrier to meeting business requirements.

    Each of these practices represents a trade-off. Understand risks before implementing any of these practices.

    Scheduling of Restore Preparation

    Technical challenge: restore time

    Trade-off: increased ongoing overhead for backup processing

    Backup data can be prepared for restore any time after it is produced and before it is used for restore. To expedite recovery, incremental backups can be pre-applied to the prior full backup to enable faster recovery. This may be done at the expense of recovery points, or at the expense of storage by maintaining copies of unmerged full and incremental backup directories.

    Moving Restored Data

    Technical challenge: disk space limitations

    Trade-off: modification of backup directory contents

    Suggested method for moving restored data is to use --copy-back as this method provides added safety. Where you might instead optimize for disk space savings, system resources, and time you may choose to instead use MariaDB Enterprise Backup's --move-back option. Speed benefits are only present when backup files are on the same disk partition as the destination data directory.

    The --move-back option will result in the removal of all data files from the backup directory, so it is best to use this option only when you have an additional copy of your backup data in another location.

    To restore from a backup by moving files, use the --move-back option:

    Technical challenge:: CPU bottlenecks

    Trade-off: Increased workload during backups

    MariaDB Enterprise Backup is a multi-threaded application that by default runs on a single thread. In cases where you have a host with multiple cores available, you can specify the number of threads you want it to use for parallel data file transfers using the --parallel option:

    Technical challenge: Backup resource overhead, backup duration

    Trade-off: Increased restore complexity, restore process duration

    Under normal operation an incremental backup is taken against an existing full backup. This allows you to further shorten the amount of time MariaDB Enterprise Backup locks MariaDB Enterprise Server while copying tablespaces. You can then apply the changes in the increment to the full backup with a --prepare operation at leisure, without disrupting database operations.

    MariaDB Enterprise Backup also supports incrementing from an incremental backup. In this operation, the --incremental-basedir option points not to the full backup directory but rather to the previous incremental backup.

    In preparing a backup to restore the data directory, apply the chain of incremental backups to the full backup in order. That is, first inc1/, then inc2/, and so on:

    Continue to apply all the incremental changes until you have applied all available to the backup. Then restore as usual:

    Start MariaDB Enterprise Server on the restored data directory.

    Technical challenge: Backup resource overhead, backup duration.

    Trade-off: Limited to platforms with volume-level snapshots, may require crash recovery.

    While MariaDB Enterprise Backups produces file-level backups, users on storage solutions may prefer to instead perform volume-level snapshots to minimize resource impact. This storage capability exists with some SAN, NAS, and volume manager platforms.

    Snapshots occur point-in-time, so no preparation step is needed to ensure data is internally consistent. Snapshots occur while tablespaces are open, and a restored snapshot may need to undergo crash recovery.

    Just as traditional full, incremental, and partial backups should be tested, so too should recovery from snapshots be tested on an ongoing basis.

    MariaDB Server includes functionality to reduce the impact of backup operations:

    1. Connect with a client and issue a BACKUP STAGE START statement and then a BACKUP STAGE BLOCK_COMMIT statement.

    2. Take the snapshot.

    This page is: Copyright © 2025 MariaDB. All rights reserved.

    Point-In-Time Recovery (InnoDB Log Archiving)

    Perform point-in-time recovery in MariaDB by replaying archived InnoDB write-ahead logs at startup to restore the server to a specific Log Sequence Number (LSN).

    This functionality is available from MariaDB 13.0.

    When InnoDB log archiving is enabled, the server retains a continuous history of write-ahead log records across multiple ib_lsn.log files. You can use this history to perform point-in-time recovery (PITR) to a specific Log Sequence Number (LSN), by replaying the archived InnoDB write-ahead logs at server startup.

    This is an alternative to PITR via mariadb-backup and binary logs, useful in InnoDB-only deployments or in recovery scenarios where binary logs are not available.

    No shipped backup tool yet generates or restores backups in the innodb_log_archive=ON format — does not support it and fails when the server is running with innodb_log_archive=ON. A backup tool that uses this format is being worked on. Until it ships, this procedure assumes you already have an externally-prepared restore that contains a consistent set of ib_lsn.log files alongside the InnoDB data files.

    Recovery Parameters

    Two startup parameters define the range of the log replay:

    • — the LSN at which recovery begins. Set this to the end LSN of the previous restore when applying an incremental restore. The default 0 starts from the latest completed checkpoint, which is guaranteed to live in one of the last two ib_lsn.log files.

    • — the LSN at which recovery ends (the recovery point objective). When this is non-zero, persistent InnoDB tables become read-only and no log writes are allowed during the recovery session. The default 0 replays the log to its end.

    You can identify candidate LSNs from the status variable on the source server, and from the file names in the data directory (each ib_lsn.log file name encodes the LSN at file offset 0x3000).

    The data files in the restore must correspond to an LSN that lies between Innodb_lsn_archived (the first checkpoint in the first archived log file) and the end LSN of the last archived log file. To extend the available recovery range, copy additional archived log files in from the source server — no further copying of data files is required.

    1

    Prepare the restore.

    Place the restored InnoDB data files and the corresponding ib_lsn.log archive files in the data directory. With innodb_log_archive=ON, the server refuses to start if a legacy ib_logfile0 exists, so make sure it is not present.

    2
    • — feature overview, file format, monitoring, and managing archived log files.

    • , , .

    • — the binary-log-based PITR procedure.

    Replication as a Backup Solution

    Explore how to use replication as part of your backup strategy, allowing you to offload backup tasks to a replica server to reduce load on the primary.

    Replication can be used to support the backup strategy.

    Replication alone is not sufficient for backup. It assists in protecting against hardware failure on the primary server, but does not protect against data loss. An accidental or malicious DROP DATABASE or TRUNCATE TABLE statement are replicated onto the replica as well. Care needs to be taken to prevent data getting out of sync between the primary and the replica.

    The terms master and slave have historically been used in replication, and MariaDB has begun the process of adding primary and replica synonyms. The old terms will continue to be used to maintain backward compatibility - see to follow progress on this effort.

    Replication is most commonly used to support backups as follows:

    • A primary server replicates to a replica

    • Backups are then run off the replica without any impact on the primary.

    Backups can have a significant effect on a server, and a high-availability primary may not be able to be stopped, locked or simply handle the extra load of a backup. Running the backup from a replica has the advantage of being able to shutdown or lock the replica and perform a backup without any impact on the primary server.

    Note that when backing up off a replica server, it is important to ensure that the servers keep the data in sync. See for example for a situation when identical statements can result in different data on a replica and a primary.

    To set up a replica specifically for backup purposes, you will need to configure outbound replication from your primary server to the replica. Here is a step-by-step guide to establishing this connection securely:

    On the primary server, create a dedicated user for replication and grant it the necessary privileges:

    (Optional: Confirm the grants by executing SHOW GRANTS FOR 'backup_replica'@'replica_ip_or_hostname';)

    On the primary server, obtain the current GTID position from which the replica should start replicating. If you want to start from the most recent transaction, query the gtid_current_pos:

    On the replica server, configure the starting GTID position using the value obtained in the previous step:

    SQL

    On the replica server, configure the connection to the primary server using the CHANGE MASTER TO statement:

    (Note: Adjust the MASTER_PORT, MASTER_SSL, and add MASTER_SSL_CA parameters as necessary depending on your network and security configuration).

    On the replica server, start the replication process:

    On the replica server, verify that replication is running smoothly:

    Ensure that both Slave_IO_Running and Slave_SQL_Running are Yes. Once the replica is fully synced, you can safely pause it or run your backup tools (mariadb-backup or mariadb-dump) directly against this replica without affecting the primary server's performance.

    This page is licensed: CC BY-SA / Gnu FDL

    Backup and Restore via dbForge Studio

    Learn how to use dbForge Studio, a GUI tool, to perform backup and restore operations for MariaDB databases visually.

    dbForge Studio is a proprietary third-party tool, not included with MariaDB Server. Content contributed by devart.

    In the modern world, data importance is non-negotiable, and keeping data integrity and consistency is the top priority. Data stored in databases is vulnerable to system crashes, hardware problems, security breaches, and other failures causing data loss or corruption. To prevent database damage, it is important to back the data up regularly and implement the data restore policies. MariaDB, one of the most popular database management systems, provides several methods to configure routines for backing up and recovering data. The current guideline illustrates both processes performed with the help of dbForge Studio for MySQL which is also a fully-functional GUI client for MariaDB that has everything you need to accomplish the database-related tasks on MariaDB.

    Create the backup on MariaDB

    dbForge Studio for MySQL and MariaDB has a separate module dedicated to the data backing up and recovering jobs. Let us first look at how set the tool to create a MariaDB backup. Launch the Studio and go to Database > Backup and Restore > Backup Database. The Database Backup Wizard with several pages will appear. On the General page, specify the database in question and how to connect to it, then choose where to save the created backup file, and specify its name. There are additional optional settings – you can select to delete old files automatically, zip the output backup file, etc. When done, click Next.

    b1

    On the Backup content page, select the objects to back up. Click Next.

    The Options page. Here you can specify the details of the data backing up process. Plenty of available options allow you to configure this task precisely to meet the specific requirements. When done, click Next.

    The Errors handling page. Here you configure how the Studio should handle the errors that might occur during the backing up process. Also, you can set the Studio to write the information about the errors it encountered into the log file.

    You can save the project settings to apply them in the future. For this, in the left bottom corner of the Wizard, select one of the saving options: Save Project or Save Command Line. The latter allows saving settings as a backup script which you can execute from the command line at any time later.

    The configuration process is complete. Click Backup to launch the data backing up.

    Note: It is not obligatory to go through all the pages of the Wizard. The Backup button is available no matter on which page you are. Thus, you can launch the process of backing the data up whenever you have set everything you needed.

    After you have clicked Backup, dbForge Studio for MySQL starts to create a MariaDB backup.

    When this is done, you will see the confirmation message. Click Finish.

    Backup and restore policies suggest creating regular backups on a daily, weekly, monthly, quarterly, and yearly basis. Besides, to minimize the consequences of possible data loss, it is highly recommended make a backup before making any changes to a database, such as upgrading, modifying data, redesigning the structure, etc. Simply speaking, you always need a fresh backup to restore the most up-to-date database version. To ensure regular backups on schedule, you can use a batch file created with the help of the Studio and Windows Task Scheduler, where you need to create and schedule the backup task.

    This is an even faster task, done in half as many steps.

    The process of data recovery from the backup file is simple. It only takes several clicks: Launch dbForge Studio for MySQL and go to Database > Backup and Restore > Restore Database. The Database Restore Wizard will appear. Specify the database name, its connection parameters, and the path to the backup file you want to restore. Then click Restore, and the process will start immediately.

    When the process is complete, click Finish.

    More information about this essential feature is available on the – it explores the routines performed on MySQL, but they fully apply to MariaDB backups. You can use the same IDE and the same workflow.

    To test-drive this and other features of the Studio (the IDE includes all the tools necessary for the development, management, and administration of databases on MariaDB), . dbForge Studio for MySQL and MariaDB boasts truly advanced functionality that will help your teams deliver more value.

    This page is licensed: CC BY-SA / Gnu FDL

    KEY Partitioning Type

    Understand KEY partitioning, similar to HASH but using MariaDB's internal hashing function on one or more columns to distribute data.

    Syntax

    PARTITION BY KEY
    [ALGORITHM={MYSQL51|MYSQL55|BASE31|CRC32C|XXH32|XXH3}]
    ([column_names])
    [PARTITIONS (number_of_partitions)]
    • MYSQL51 and MYSQL55 are existing algorithms, with MYSQL55 being the default, also used by default before 12.3

    • CRC32C, XXH32, and XXH3 use the established hash algorithms of the same names. These are recommended algorithms to use.

    • BASE31 uses a base-31 representation of the bytes and serves as a simple baseline that is more evenly distributed than MYSQL51 or MYSQL55 for simple sequential data.

    Partitioning by key is a type of partitioning that is similar to and can be used in a similar way as .

    KEY takes an optional list of column_names, and the hashing function is given by the server.

    Compared to HASH partitioning, KEY partitioning distributes data using a preset hash algorithms on the specified columns, rather than an expression specified by the user.

    If no column_names are specified, the table's primary key is used if present, or not null unique key if no primary key is present. If neither of these keys are present, not specifying any column_names will result in an error:

    Unlike other partitioning types, columns used for partitioning by KEY are not limited to integer or NULL values.

    KEY partitions do not support column index prefixes. Any columns in the partitioning key that make use of column prefixes are not used.

    The unique key must be NOT NULL:

    KEY requires column_values if no primary key or not null unique key is present:

    Primary key columns with index prefixes are silently ignored, so the following two queries are equivalent:

    a(5) and c(5) are silently ignored in the former.

    If all columns use index prefixes, the statement fails with a slightly misleading error:

    This page is licensed: CC BY-SA / Gnu FDL

    Stored Routine Privileges

    This page explains the privileges required to create, alter, execute, and drop stored routines, including the automatic grants for creators.

    It's important to give careful thought to the privileges associated with stored functions and stored procedures. The following is an explanation of how they work.

    Creating Stored Routines

    • To create a stored routine, the CREATE ROUTINE privilege is needed. The SUPER privilege is required if a DEFINER is declared that's not the creator's account (see DEFINER clause below). The SUPER privilege is also required if statement-based binary logging is used. See Binary Logging of Stored Routines for more details.

    Altering Stored Routines

    • To make changes to, or drop, a stored routine, the privilege is needed. The creator of a routine is temporarily granted this privilege if they attempt to change or drop a routine they created, unless the variable is set to 0 (it defaults to 1).

    • The SUPER privilege is also required if statement-based binary logging is used. See for more details.

    • To run a stored routine, the privilege is needed. This is also temporarily granted to the creator if they attempt to run their routine unless the variable is set to 0.

    • The (by default DEFINER) specifies what privileges are used when a routine is called. If SQL SECURITY is INVOKER, the function body are evaluated using the privileges of the user calling the function. If SQL SECURITY is

    If left out, the DEFINER is treated as the account that created the stored routine or view. If the account creating the routine has the SUPER privilege, another account can be specified as the DEFINER.

    This clause specifies the context the stored routine or view will run as. It can take two values - DEFINER or INVOKER. DEFINER is the account specified as the DEFINER when the stored routine or view was created (see the section above). INVOKER is the account invoking the routine or view.

    As an example, let's assume a routine, created by a superuser who's specified as the DEFINER, deletes all records from a table. If SQL SECURITY=DEFINER, anyone running the routine, regardless of whether they have delete privileges, are able to delete the records. If SQL SECURITY = INVOKER, the routine will only delete the records if the account invoking the routine has permission to do so.

    INVOKER is usually less risky, as a user cannot perform any operations they're normally unable to. However, it's not uncommon for accounts to have relatively limited permissions, but be specifically granted access to routines, which are then invoked in the DEFINER context.

    All privileges that are specific to a stored routine are dropped when a or DROP ROUTINE is run. However, if a or is used to drop and replace and the routine, any privileges specific to that routine will not be dropped.

    • - maria.com post on what to do after you've dropped a user, and now want to change the DEFINER on all database objects that currently have it set to this dropped user.

    This page is licensed: CC BY-SA / Gnu FDL

    Binary Logging of Stored Routines

    When binary logging is enabled, stored routines may require special handling (like SUPER privileges) if they are non-deterministic, to ensure consistent replication.

    Binary logging can be row-based, statement-based, or a mix of the two. See Binary Log Formats for more details on the formats. If logging is statement-based, it is possible that a statement will have different effects on the master and on the slave.

    Stored routines are particularly prone to this, for two main reasons:

    • stored routines can be non-deterministic, in other words non-repeatable, and therefore have different results each time they are run.

    • the slave thread executing the stored routine on the slave holds full privileges, while this may not be the case when the routine was run on the master.

    The problems with replication will only occur with statement-based logging. If row-based logging is used, since changes are made to rows based on the master's rows, there is no possibility of the slave and master getting out of sync.

    By default, with row-based replication, triggers run on the master, and the effects of their executions are replicated to the slaves. However, it is possible to run triggers on the slaves. See .

    If the following criteria are met, then there are some limitations on whether stored routines can be created:

    • The is enabled, and the system variable is set to STATEMENT. See for more information.

    • The is set to OFF, which is the default value.

    If the above criteria are met, then the following limitations apply:

    • When a is created, it must be declared as either DETERMINISTIC, NO SQL or READS SQL DATA, or else an error will occur. MariaDB cannot check whether a function is deterministic, and relies on the correct definition being used.

    • To create or modify a stored function, a user requires the SUPER privilege as well as the regular privileges. See for these details.

    A deterministic function:

    A non-deterministic function, since it uses the function:

    This page is licensed: CC BY-SA / Gnu FDL

    Basic SQL Statements Guide

    A quick reference for core SQL statements including DDL (CREATE, DROP), DML (INSERT, UPDATE, DELETE), and TCL (COMMIT, ROLLBACK) commands.

    This guide provides a quick overview of essential SQL statements in MariaDB, categorized by their function in data definition, data manipulation, and transaction control. Find brief descriptions and links to detailed documentation for each statement, along with a simple illustrative example sequence.

    (If you need a basic tutorial on how to use the MariaDB database server and execute simple commands, see . Also see for examples of commonly-used queries.)

    These statements are part of the SQL Data Definition Language - DDL.

    System & Status Variables Guide

    This guide indicates where the various system and status variables of MariaDB Server are found.

    System variables and status variables serve two distinct roles in MariaDB: System variables are the "knobs" you turn to change how the server behaves, while status variables are the "gauges" you watch to see how the server is performing.

    Because MariaDB is modular, these variables are often grouped by their specific functional area or plugin.


    System variables are configuration settings. You use them to define the environment, set resource limits, and tune performance.

    • Configuration & Tuning: You modify these to optimize the server for your workload. For example, you might increase innodb_buffer_pool_size

    Application Code

    This guide covers application-side considerations, such as using ORMs, stored procedures, and writing robust SQL that handles schema changes gracefully.

    Although relational database applications strive to separate application code from database data, this is only possible to a limited extent. That said, there are means to work with database and application design that make maintaining database schema and applications easier. The task at hand then, on the application side of things, is to make the application easy to maintain and as flexible as possible when it comes to integrating with the database on one hand, and on the other hand ensure that the measures taken don’t take a toll on features, functionality or performance.

    Using an ORM, such as Hibernate for Java applications, makes it possible to build applications that do not rely on the lowest detail of the database schema. On the other hand, performance is sometimes an issue and, in some cases, complex relational operations might still need to be hard-coded. Despite this, hibernate is often a good way to create applications and database schemas that are easy to maintain.

    Using database stored procedures is another way of isolating database logic from application logic. One advantage here is that if applications call stored procedures instead of issuing SQL statements, then we can keep a clear differentiator between the database and backend processing and application-level processing. A disadvantage is that the connection between the backend logic and the structure of the data is still there, it is just somewhere else than in the application, but this still makes maintenance easier in many ways.

    It is also common not to drive this too far, i.e. complex SQL and code that truly belongs in the backend can be in the database, whereas more basic SQL and simple SELECTs can be kept as they are in the application.

    Partition Maintenance

    Learn to maintain MariaDB partitions using ALTER TABLE. Includes syntax for optimizing and repairing partitions, plus best practices for managing time-series data and performance.

    You can perform several maintenance tasks on partitioned tables using standard SQL statements or specific ALTER TABLE extensions.

    For general maintenance, MariaDB supports the following statements on partitioned tables just as it does for non-partitioned tables:

    • CHECK TABLE

    Setting up a Replica (mariadb-backup)

    Initialize a replication slave using a backup. This guide shows how to use mariadb-backup to provision a new replica from a master server.

    This page documents how to set up a replica from a backup.

    If you are using MariaDB Galera Cluster, then you may want to try one of the following pages instead:

    The first step is to simply take and prepare a fresh full backup of a database server in the replication topology. If the source database server is the desired replication primary, then we do not need to add any additional options when taking the full backup. For example:

    Full Backup and Restore (mariadb-backup)

    Complete MariaDB backup and recovery guide. Complete resource for backup methods, mariabackup usage, scheduling, and restoration for production use.

    When using mariadb-backup, you have the option of performing a full or an incremental backup. Full backups create a complete backup of the database server in an empty directory while incremental backups update a previous backup with whatever changes to the data have occurred since the backup. This page documents how to perform full backups.

    In order to back up the database, you need to run mariadb-backup with the --backup option to tell it to perform a backup and with the --target-dir option to tell it where to place the backup files. When taking a full backup, the target directory must be empty or it must not exist.

    To take a backup, run the following command:

    The time the backup takes depends on the size of the databases or tables you're backing up. You can cancel the backup if you need to, as the backup process does not modify the database.

    Stored Procedure Overview

    Stored procedures are precompiled collections of SQL statements stored on the server, allowing for encapsulated logic, parameterized execution, and improved application performance.

    A Stored Procedure is a routine invoked with a statement. It may have input parameters, output parameters and parameters that are both input parameters and output parameters.

    Here's a skeleton example to see a stored procedure in action:

    First, the delimiter is changed, since the function definition will contain the regular semicolon delimiter. The procedure is named Reset_animal_count. MODIFIES SQL DATA indicates that the procedure will perform a write action of sorts, and modify data. It's for advisory purposes only. Finally, there's the actual SQL statement - an UPDATE.

    A more complex example, with input parameters, from an actual procedure used by banks:

    See

    Stored Aggregate Functions

    Stored Aggregate Functions allow users to create custom aggregate functions that process a sequence of rows and return a single summary result.

    are functions that are computed over a sequence of rows and return one result for the sequence of rows.

    Creating a custom aggregate function is done using the statement with two main differences:

    • The addition of the AGGREGATE keyword, so CREATE AGGREGATE FUNCTION

    Stored Function Overview

    A Stored Function is a set of SQL statements that can be called by name, accepts parameters, and returns a single value, enhancing SQL with custom logic.

    A Stored Function is a defined function that is called from within an SQL statement like a regular function and returns a single value.

    Here's a skeleton example to see a stored function in action:

    First, the delimiter is changed, since the function definition will contain the regular semicolon delimiter. See for more. Then the function is named FortyTwo and defined to return a tinyin. The DETERMINISTIC keyword is not necessary in all cases (although if binary logging is on, leaving it out will throw an error), and is to help the query optimizer choose a query plan. A deterministic function is one that, given the same arguments, will always return the same result.

    Next, the function body is placed between statements. It declares a tinyint,

    ARCHIVE

    The Archive storage engine is optimized for high-speed insertion and compression of large amounts of data, suitable for logging and auditing.

    The ARCHIVE storage engine is a storage engine that uses gzip to compress rows. It is mainly used for storing large amounts of data, without indexes, with only a very small footprint.

    A table using the ARCHIVE storage engine is stored in two files on disk. There's a table definition file with an extension of .frm, and a data file with the extension .ARZ. At times during optimization, a .ARN file will appear.

    New rows are inserted into a compression buffer and are flushed to disk when needed. SELECTs cause a flush. Sometimes, rows created by multi-row inserts are not visible until the statement is complete.

    ARCHIVE allows a maximum of one key. The key must be on an column, and can be a PRIMARY KEY

    Storage Engines

    Understand MariaDB Server's storage engines. Explore the features and use cases of InnoDB, Aria, MyISAM, and other engines to choose the best option for your specific data needs.

    An introduction to MariaDB's pluggable storage engine architecture, highlighting key engines like InnoDB, MyISAM, and Aria for different workloads.

    A guide to selecting the appropriate storage engine based on data needs, comparing features of general-purpose, columnar, and specialized engines.

    How mariadb-backup Works

    Deep dive into backup mechanics. Understand how the tool handles redo logs, locking, and file copying to ensure consistent backups.

    This is a description of the different stages in mariadb-backup, what they do and why they are needed.

    • Connect to mysqld instance, find out important variables (datadir, InnoDB pagesize, encryption keys, encryption plugin etc)

    • Scan the database directory, datadir

    ) is generally preferred for character sets, and consistency in collations simplifies maintenance.
  • Numeric: Use BIGINT for auto-generated primary keys to prevent overflow issues. Avoid FLOAT and DOUBLE for monetary values due to rounding issues; DECIMAL is more accurate.

  • Temporal: Understand the differences between DATETIME (stores time as is) and TIMESTAMP (affected by client-side time zones) before using them.

  • Other: Be cautious with ENUM and SET types, as adding values requires schema alteration.

  • Stored Procedures and Functions: Isolate database logic from application logic, making maintenance easier by centralizing complex SQL operations in the database layer.
  • Best Practices in Application SQL:

    • Avoid SELECT *: Explicitly list columns to prevent issues if table schema changes (column order or addition).

    • Avoid INSERT without column names: Always specify column names in INSERT statements to avoid errors when table schema changes.

    • Processing of column data: Be consistent; processing in the application can sometimes make SQL more readable.

    • Use of reserved words: Avoid using SQL reserved words for schema objects and column names, even if quoting them makes them valid.

    • Relying on non-explicit assumptions: Never assume row ordering without an ORDER BY clause. The order of returned rows is otherwise undetermined. Be cautious with LIMIT in UPDATE or DELETE without ORDER BY.

  • Replication: Use MariaDB replication, particularly statement-based replication (SBR), for canary testing by replicating from the production system to a new server with the updated schema.

  • Invisible Columns: A MariaDB feature allowing columns to exist without being exposed by default, useful in scenarios where old applications use SELECT * or INSERT without column names, allowing new columns to be added without breaking existing code.

  • In This Guide

    Introduction & Background
    Database Design
    Application Code
    Canary Testing
    ARCHIVE

    The Archive storage engine is optimized for high-speed insertion and compression of large amounts of data, suitable for logging and auditing.

    ARIA

    Learn about the Aria storage engine in MariaDB Server. Understand its features, advantages, and use cases, particularly for crash-safe operations and transactional workloads.

    BLACKHOLE

    The BLACKHOLE storage engine discards all data written to it but records operations in the binary log, useful for replication filtering and testing.

    CONNECT

    The main characteristic of CONNECT is to enable accessing data scattered on a machine as if it was a centralized database.

    CSV

    The CSV storage engine stores data in text files using comma-separated values format, allowing easy data exchange with other applications.

    FederatedX

    FederatedX is a storage engine that allows access to tables on remote MariaDB or MySQL servers as if they were local tables.

    InnoDB

    Discover InnoDB, the default storage engine for MariaDB Server. Learn about its transaction-safe capabilities, foreign key support, and high performance for demanding workloads.

    MEMORY

    The MEMORY storage engine stores tables in RAM for fast access, but data is lost upon server restart.

    MERGE

    The MERGE storage engine allows a collection of identical MyISAM tables to be treated as a single logical table, useful for managing large datasets.

    Mroonga

    Mroonga (formerly named Groonga Storage Engine) is a storage engine that provides fast CJK-ready full text searching using column store.

    MyISAM

    Explore the MyISAM storage engine in MariaDB Server. Understand its characteristics, including suitability for read-heavy workloads, and its role in specific use cases.

    MyRocks

    Learn about the MyRocks storage engine in MariaDB Server. Discover its advantages for flash storage, high write throughput, and compression efficiency in modern database deployments.

    OQGRAPH

    Explore the OQGRAPH storage engine in MariaDB Server. Learn how to efficiently manage hierarchical and complex graph data structures, perfect for social networks and bill of materials.

    PERFORMANCE_SCHEMA

    While technically a storage engine, PERFORMANCE_SCHEMA provides a way to inspect internal server execution details at a low level.

    SEQUENCE Storage Engine

    The Sequence engine generates virtual tables of number sequences on the fly, useful for generating series of integers without storing data.

    S3 Storage Engine

    Integrate MariaDB Server with Amazon S3 using the S3 Storage Engine. Learn how to store and retrieve data directly from cloud object storage for scalability and cost efficiency.

    SphinxSE

    Integrate MariaDB Server with Sphinx for advanced full-text search. The Sphinx storage engine allows you to query external Sphinx indexes directly from your database.

    Spider

    Explore the Spider storage engine in MariaDB Server. Learn how to shard data across multiple MariaDB and MySQL servers, enabling horizontal scaling and distributed database solutions.

    VIDEX Storage Engine

    The VIDEX storage engine is an aggregated, extensible engine suitable for what-if analyses in MariaDB. The name is derived from [VI]rtual in[DEX].

    Converting Tables from MyISAM to InnoDB

    This guide outlines the benefits and process of migrating tables from MyISAM to InnoDB, highlighting key differences like transaction support and foreign keys.

    Machine Learning with MindsDB

    Learn how to integrate MindsDB with MariaDB to train and query machine learning models directly using standard SQL commands.

    Legacy Storage Engines

    Explore legacy storage engines in MariaDB Server. This section provides information on older engines, their historical context, and considerations for migration or compatibility.

    Storage Engines Overview
    Choosing the Right Storage Engine
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    spinner
    ALTER FUNCTION
    SHOW CREATE FUNCTION
    SHOW FUNCTION STATUS
    Stored Routine Privileges
    INFORMATION_SCHEMA ROUTINES Table
    spinner
    spinner
    spinner
    spinner
    SHOW CREATE PROCEDURE
    SHOW PROCEDURE STATUS
    Information Schema ROUTINES Table
    spinner

    Restore the backup file on MariaDB

    dedicated backup and restore page
    download dbForge Studio for a free 30-day trial
    b2
    b3
    b4
    b5
    b6
    r1
    r2
    spinner
    DEFINER
    , the function body is always evaluated using the privileges of the definer account.
    DEFINER
    is the default. Thus, by default, users who can access the database associated with the stored routine can also run the routine, and potentially perform operations they wouldn't normally have permissions for.
  • The creator of a routine is the account that ran the CREATE FUNCTION or CREATE PROCEDURE statement, regardless of whether a DEFINER is provided. The definer is by default the creator unless otherwise specified.

  • The server automatically changes the privileges in the mysql.proc table as required, but will not look out for manual changes.

  • Running Stored Routines

    DEFINER Clause

    SQL SECURITY Clause

    Dropping Stored Routines

    See Also

    ALTER ROUTINE
    automatic_sp_privileges
    Binary Logging of Stored Routines
    EXECUTE
    automatic_sp_privileges
    SQL SECURITY clause
    DROP FUNCTION
    CREATE OR REPLACE FUNCTION
    CREATE OR REPLACE PROCEDURE
    Changing the DEFINER of MySQL stored routines etc.
    spinner

    Stop the MariaDB Server (if it is running).

    3

    Start the server with recovery parameters.

    Pass innodb_log_recovery_start and innodb_log_recovery_target either on the command line or in the configuration file, alongside innodb_log_archive=ON. While innodb_log_recovery_target is non-zero, the server replays the archived log up to the target LSN and then keeps the InnoDB tables read-only.

    4

    Verify the state.

    Once the server reaches the target LSN, the recovery process stops. Inspect Innodb_lsn_archived, Innodb_lsn_current, and the contents of the recovered tables to confirm the data is at the expected logical point.

    5

    Resume normal operation.

    To return to normal read-write operation, restart the server without innodb_log_recovery_target set.

    Procedure

    No data file may carry an LSN newer than innodb_log_recovery_target. Crash recovery's role is to bring every database page to the same LSN. If any data file is newer than the target, recovery completes in an inconsistent state where some pages carry an LSN past the target — the database is corrupted. The server cannot validate every such impossible target, and the resulting corruption may not surface until the affected pages are accessed (see MDEV-34830). See innodb_log_recovery_target for details.

    Point-in-time recovery of DDL operations is limited even for an InnoDB-only deployment, because part of the data dictionary is stored in .frm files whose creation is not covered by the InnoDB write-ahead log.

    See Also

    innodb_log_recovery_start
    innodb_log_recovery_target
    Innodb_lsn_archived
    InnoDB Log Archiving
    innodb_log_archive
    innodb_log_recovery_start
    innodb_log_recovery_target
    Point-In-Time Recovery (PITR, mariadb-backup)
    mariadb-backup
    root
    user.
  • Configuring MariaDB as a service and setting the port (default is 3306).

  • Optionally, enabling UTF8 as the default server character set.

  • spinner
    spinner
    unit: The unit of the interval (e.g., HOUR, MINUTE, DAY, MONTH, YEAR, etc.).

    Tracking Date Changes with Time: Using DATETIME

    Adding Durations with DATE_ADD

    Date Calculations Across Months and Years with DATE_ADD

    Subtracting Durations

    spinner

    --lock-tables (or -x): Locks all tables across all databases before starting the backup to ensure data consistency. The lock is released once the dump is complete for each table. For transactional tables like InnoDB, using --single-transaction is often preferred as it provides a consistent snapshot without prolonged locking of all tables.

  • --all-databases (or -A): Specifies that all databases should be dumped.

  • > /data/backup/dbs_alldatabases.sql: Redirects the output (the SQL statements) to the specified file. Ensure the path exists and the user running the command has write permissions.

  • option is
    not
    used when dumping specific tables in this manner.
    ,
    PROCESS
    and
    RELOAD
    might be required. A user with global
    SELECT
    ,
    LOCK TABLES
    ,
    SHOW VIEW
    ,
    EVENT
    , and
    TRIGGER
    privileges is often used for backups.
  • Consistency with InnoDB: For databases primarily using InnoDB tables, consider using the --single-transaction option instead of --lock-tables. This option starts a transaction before dumping and reads data from a consistent snapshot without locking the tables for extended periods, allowing concurrent reads and writes.Bash

  • Practice Makes Perfect: mariadb-dump is powerful but can have many options. Practice using it on a test database or server to become comfortable with its usage and to verify that your backup strategy works as expected.

  • Test Your Backups: Regularly test your backup files by restoring them to a non-production environment to ensure they are valid and can be used for recovery.

  • Restoration: To learn how to restore data from these dump files, see the "Data Restoration Guide".

  • Security: Store backup files in a secure location. If passwords are included in scripts, ensure the script files have restricted permissions.

  • Backing Up All Databases

    Backing Up a Single Database

    Backing Up Specific Tables

    Important Considerations and Best Practices

    spinner

    Text / String Data Types

    Character Sets and Collations

    Best Practices With Regard to String Data Types

    Numeric Data Types

    Temporal Data Types

    Other Data Types

    Schema Objects

    Views

    See Also

    Data types
    Character sets and collations
    Views
    Automated testing of backups.

    Applying written and tested recovery procedures, which designate the systems and commands to be used during recovery.

  • Performing drills and exercises that periodically test recovery procedures to confirm readiness.

  • Retention requirements and the run-rate of new data production can aid in capacity planning.

    Recovery Objectives

    Achieving RPO

    Achieving RTO

    Replication Considerations

    Encryption Considerations

    Backup Storage Considerations

    Backup Testing

    data inventory
    spinner
    Issue a BACKUP STAGE END statement.
  • Once the backup has been completed, remove all files which begin with the #sql prefix. These files are generated when ALTER TABLE occurs during a staged backup.

  • Retrieve, copy, or store the snapshot as is typical for your storage platform and as per business requirements to make the backup durable. This may require mounting the snapshot in some manner.

  • It is recommended to briefly prevent writes while snapshotting. Specific commands vary depending on storage platform, business requirements, and setup, but a general approach is to:

    1. Connect with a client and issue a FLUSH TABLES WITH READ LOCK statement, leaving the client connected.

    2. Take the snapshot.

    3. Issue an UNLOCK TABLES statement, to remove the read lock.

    4. Retrieve, copy, or store the snapshot as is typical for your storage platform and as per business requirements to make the backup durable. This may require mounting the snapshot in some manner.

    Multithreading

    Incrementing an Incremental Backup

    Storage Snapshots

    Taking Snapshots

    advanced backup
    spinner

    Description

    Examples

    partitioning by hash
    PARTITION BY KEY ([column_names])
    [PARTITIONS (number_of_partitions)]
    spinner

    Triggers work in the same way, except that they are always assumed to be deterministic for logging purposes, even if this is obviously not the case, such as when they use the UUID function.

  • Triggers can also update data. The slave uses the DEFINER attribute to determine which user is taken to have created the trigger.

  • Note that the above limitations do no apply to stored procedures or to events.

  • How MariaDB Handles Statement-Based Binary Logging of Routines

    Examples

    Running triggers on the slave for Row-based events
    binary log
    binlog_format
    Binary Log Formats
    log_bin_trust_function_creators
    stored function
    Stored Routine Privileges
    UUID_SHORT
    spinner
    mariadb-backup writes the backup files the target directory. If the target directory doesn't exist, it creates it. If the target directory exists and contains files, it raises an error and aborts.

    Here is an example backup directory:

    You can optionally use the --history option to record metadata about your full backup in the database. This creates a centralized log and allows future incremental backups to reference this full backup by name instead of by directory path.

    • Privileges: The backup user requires INSERT, CREATE, and ALTER privileges on the history table (mysql.mariadb_backup_history in MariaDB 10.11+, or PERCONA_SCHEMA.xtrabackup_history in older versions).

    • Failure Case: If the user lacks privileges, the backup will complete the file copy process but will fail at the final step with an INSERT command denied error.

    The data files that mariadb-backup creates in the target directory are not point-in-time consistent, given that the data files are copied at different times during the backup operation. If you try to restore from these files, InnoDB notices the inconsistencies and crashes to protect you from corruption

    Before you can restore from a backup, you first need to prepare it to make the data files consistent. You can do so with the --prepare option.

    1. Run mariadb-backup --backup. You must use a version of mariadb-backup that is compatible with the server version you are planning to upgrade from. For instance, when upgrading from MariaDB 10.4 to 10.5, you must use the 10.4 version of mariadb-backup, Another example: When upgrading from MariaDB 10.6 to 10.11, you must use the 10.6 version of mariadb-backup.

    2. Run mariadb-backup --prepare, again using a compatible version of mariadb-backup, as described in the previous step.

    Once the backup is complete and you have prepared the backup for restoration (previous step), you can restore the backup using either the --copy-back or the --move-back options. The --copy-back option allows you to keep the original backup files. The --move-back option actually moves the backup files to the datadir, so the original backup files are lost.

    • First, stop the MariaDB Server process.

    • Then, ensure that datadir is empty.

    • Then, run mariadb-backup with one of the options mentioned above:

    • Then, you may need to fix the file permissions.

    When mariadb-backup restores a database, it preserves the file and directory privileges of the backup. However, it writes the files to disk as the user and group restoring the database. As such, after restoring a backup, you may need to adjust the owner of the data directory to match the user and group for the MariaDB Server, typically mysql for both. For example, to recursively change ownership of the files to the mysql user and group, you could execute:

    • Finally, start the MariaDB Server process.

    Once a full backup is prepared, it is a fully functional MariaDB data directory. Therefore, as long as the MariaDB Server process is stopped on the target server, you can technically restore the backup using any file copying tool, such as cp or rsync. For example, you could also execute the following to restore the backup:

    This page is licensed: CC BY-SA / Gnu FDL

    mariadb-backup was previously called mariabackup.

    For a complete list of mariadb-backup options, see this page.

    For a detailed description of mariadb-backup functionality, see this page.

    Backing up the Database Server

    Using the Backup History Feature

    Preparing the Backup for Restoration

    Backup Preparation Steps

    Restoring the Backup

    Restoring with Other Tools

    spinner
    for full syntax details.

    Security is a key reason. Banks commonly use stored procedures so that applications and users don't have direct access to the tables. Stored procedures are also useful in an environment where multiple languages and clients are all used to perform the same operations.

    To find which stored functions are running on the server, use SHOW PROCEDURE STATUS.

    or query the routines table in the INFORMATION_SCHEMA database directly:

    To find out what the stored procedure does, use SHOW CREATE PROCEDURE.

    To drop a stored procedure, use the DROP PROCEDURE statement.

    To change the characteristics of a stored procedure, use ALTER PROCEDURE. However, you cannot change the parameters or body of a stored procedure using this statement; to make such changes, you must drop and re-create the procedure using CREATE OR REPLACE PROCEDURE (which retains existing privileges), or DROP PROCEDURE followed CREATE PROCEDURE .

    See the article Stored Routine Privileges.

    This page is licensed: CC BY-SA / Gnu FDL

    Creating a Stored Procedure

    CALL
    CREATE PROCEDURE

    Why use Stored Procedures?

    Stored Procedure listings and definitions

    Dropping and Updating a Stored Procedure

    Permissions in Stored Procedures

    spinner
    $ sudo systemctl stop mariadb
    mariadb -u root -p
    mariadb --user your_username --password your_database_name < /path/to/your/backupfile.sql
    -- Connect to MariaDB as an administrative user (e.g., root)
    CREATE USER 'admin_restore_temp'@'localhost' IDENTIFIED BY 'its_very_secure_pwd';
    
    -- Grant general SELECT on the database (might be needed if dump file structure requires it)
    -- Or, if not needed, ensure the user can at least USE the database.
    GRANT SELECT ON your_database_name.* TO 'admin_restore_temp'@'localhost';
    
    -- Grant full privileges ONLY on the table to be restored
    GRANT ALL PRIVILEGES ON your_database_name.table_to_restore TO 'admin_restore_temp'@'localhost';
    
    FLUSH PRIVILEGES;
    mariadb --user admin_restore_temp --password --force your_database_name < /path/to/your/fulldumpfile.sql
    DROP USER 'admin_restore_temp'@'localhost';
    -- Example: Calculating a promised time 2 hours (7200 seconds) from current time
    INSERT INTO tickets (client_id, urgency, trouble, ticket_date, entered, promised)
    VALUES ('some_client', 'ASAP', 'Issue details',
            CURDATE(), CURTIME(),
            SEC_TO_TIME(TIME_TO_SEC(CURTIME()) + 7200));
    -- Corrected calculation for 'promised' TIME, wraps around 24 hours
    SEC_TO_TIME((TIME_TO_SEC(CURTIME()) + 7200) % 86400)
    INSERT INTO tickets (client_id, urgency, trouble, entered, promised)
    VALUES ('some_client', 'ASAP', 'Issue details',
            NOW(),
            DATE_ADD(NOW(), INTERVAL 2 HOUR));
    -- Add 2 hours and 30 minutes
    DATE_ADD(NOW(), INTERVAL '2:30' HOUR_MINUTE)
    -- Add 5 days
    DATE_ADD(NOW(), INTERVAL 5 DAY)
    -- Add 2 days and 6 hours
    DATE_ADD(NOW(), INTERVAL '2 6' DAY_HOUR)
    -- Add 1 year and 2 months
    DATE_ADD(NOW(), INTERVAL '1-2' YEAR_MONTH) -- Note: Original text used '1 2', '1-2' is common for YEAR_MONTH
    -- Subtract 5 days
    DATE_ADD(NOW(), INTERVAL -5 DAY)
    -- Subtract 5 days
    DATE_SUB(NOW(), INTERVAL 5 DAY)
    mariadb-dump --user=admin_backup --password --single-transaction --extended-insert --databases your_innodb_database > /data/backup/your_innodb_database.sql
    mariadb-dump --user=admin_backup --password --lock-tables --all-databases > /data/backup/dbs_alldatabases.sql
    mariadb-dump --user=admin_backup --password=yoursecurepassword --lock-tables --extended-insert --all-databases > /data/backup/dbs_alldatabases.sql
    mariadb-dump --user=admin_backup --password --lock-tables --extended-insert --databases your_database_name > /data/backup/your_database_name.sql
    mariadb-dump --user=admin_backup --password --lock-tables --extended-insert --databases db1_name db2_name > /data/backup/selected_databases.sql
    mariadb-dump --user=admin_backup --password --lock-tables --extended-insert your_database_name table_name1 table_name2 > /data/backup/your_database_name_selected_tables.sql
    CREATE VIEW orders_v_1
    AS
    SELECT o.`order_id`, o.`order_date` FROM `orders_t` o;
    mariadb-backup --backup \
          --target-dir=/data/backups/full \
          --user=mariadb-backup \
          --password=mbu_passwd \
          --ssl-ca=/etc/my.cnf.d/certs/ca.pem \
          --ssl-cert=/etc/my.cnf.d/certs/client-cert.pem \
          --ssl-key=/etc/my.cnf.d/certs/client-key.pem
    mariadb-backup --move-back --target-dir=/data/backups/full
    mariadb-backup --backup \
          --target-dir=/data/backups/full \
          --user=mariadb-backup \
          --password=mbu_passwd \
          --parallel=12
    mariadb-backup --backup \
          --incremental-basedir=/data/backups/inc1 \
          --target-dir=/data/backups/inc2 \
          --user=mariadb-backup \
          --password=mbu_passwd
    mariadb-backup --prepare \
          --target-dir=/data/backups/full \
          --incremental-dir=/data/backups/inc1
    mariadb-backup --prepare \
          --target-dir=/data/backups/full \
          --incremental-dir=/data/backups/inc2
    mariadb-backup --copy-back --target-dir=/data/backups/full
    chown -R mysql:mysql /var/lib/mysql
     ERROR 1488 (HY000): Field in list of fields for partition function not found in table
    CREATE OR REPLACE TABLE t1 (v1 INT)
      PARTITION BY KEY (v1)
      PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (v1 INT, v2 INT)
      PARTITION BY KEY (v1,v2)
      PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        id INT NOT NULL PRIMARY KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        id INT NOT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        id INT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    ERROR 1488 (HY000): Field in list of fields for partition function not found in table
    CREATE OR REPLACE TABLE t1 (
        id INT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    ERROR 1488 (HY000): Field in list of fields for partition function not found in table
    CREATE OR REPLACE TABLE t1 (
        id INT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY(name)
    PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        a VARCHAR(10),
        b VARCHAR(10),
        c VARCHAR(10),
        PRIMARY KEY (a(5), b, c(5))
    ) PARTITION BY KEY() PARTITIONS 2;
    
    CREATE OR REPLACE TABLE t1 (
        a VARCHAR(10),
        b VARCHAR(10),
        c VARCHAR(10),
        PRIMARY KEY (b)
    ) PARTITION BY KEY() PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        a VARCHAR(10),
        b VARCHAR(10),
        c VARCHAR(10),
        PRIMARY KEY (a(5), b(5), c(5))
    ) PARTITION BY KEY() PARTITIONS 2;
    ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
    DELIMITER //
     
    CREATE FUNCTION trust_me(x INT)
    RETURNS INT
    DETERMINISTIC
    READS SQL DATA
    BEGIN
       RETURN (x);
    END //
     
    DELIMITER ;
    DELIMITER //
    
    CREATE FUNCTION dont_trust_me()
    RETURNS INT
    BEGIN
       RETURN UUID_SHORT();
    END //
    
    DELIMITER ;
    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    $ ls /var/mariadb/backup/
    
    aria_log.0000001  mysql                   xtrabackup_checkpoints
    aria_log_control  performance_schema      xtrabackup_info
    backup-my.cnf     test                    xtrabackup_logfile
    ibdata1           xtrabackup_binlog_info
    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword \
       --history=full_backup_weekly
    $ mariadb-backup --prepare \
       --target-dir=/var/mariadb/backup/
    $ mariadb-backup --copy-back \
       --target-dir=/var/mariadb/backup/
    $ chown -R mysql:mysql /var/lib/mysql/
    $ rsync -avrP /var/mariadb/backup /var/lib/mysql/
    $ chown -R mysql:mysql /var/lib/mysql/
    DELIMITER //
    
    CREATE PROCEDURE Reset_animal_count() 
     MODIFIES SQL DATA
     UPDATE animal_count SET animals = 0;
    //
    
    DELIMITER ;
    SELECT * FROM animal_count;
    +---------+
    | animals |
    +---------+
    |     101 |
    +---------+
    
    CALL Reset_animal_count();
    
    SELECT * FROM animal_count;
    +---------+
    | animals |
    +---------+
    |       0 |
    +---------+
    CREATE PROCEDURE
      Withdraw                             /* Routine name */
      (parameter_amount DECIMAL(6,2),     /* Parameter list */
      parameter_teller_id INTEGER,
      parameter_customer_id INTEGER)
      MODIFIES SQL DATA                   /* Data access clause */
      BEGIN                        /* Routine body */
        UPDATE Customers
            SET balance = balance - parameter_amount
            WHERE customer_id = parameter_customer_id;
        UPDATE Tellers
            SET cash_on_hand = cash_on_hand + parameter_amount
            WHERE teller_id = parameter_teller_id;
        INSERT INTO Transactions VALUES (
            parameter_customer_id,
            parameter_teller_id,
            parameter_amount);
      END;
    SHOW PROCEDURE STATUS\G
    *************************** 1. row ***************************
                      Db: test
                    Name: Reset_animal_count
                    Type: PROCEDURE
                 Definer: root@localhost
                Modified: 2013-06-03 08:55:03
                 Created: 2013-06-03 08:55:03
           Security_type: DEFINER
                 Comment: 
    character_set_client: utf8
    collation_connection: utf8_general_ci
      Database Collation: latin1_swedish_ci
    SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES 
      WHERE ROUTINE_TYPE='PROCEDURE';
    +--------------------+
    | ROUTINE_NAME       |
    +--------------------+
    | Reset_animal_count |
    +--------------------+
    SHOW CREATE PROCEDURE Reset_animal_count\G
    *************************** 1. row ***************************
               Procedure: Reset_animal_count
                sql_mode: 
        Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `Reset_animal_count`()
        MODIFIES SQL DATA
    UPDATE animal_count SET animals = 0
    character_set_client: utf8
    collation_connection: utf8_general_ci
      Database Collation: latin1_swedish_ci
    DROP PROCEDURE Reset_animal_count();

    Used to create a new, empty database.

    DROP DATABASE

    Used to completely destroy an existing database.

    USE

    Used to select a default database for subsequent statements.

    CREATE TABLE

    Used to create a new table, which is where your data is actually stored.

    ALTER TABLE

    Used to modify an existing table's definition (e.g., add/remove columns, change types).

    DROP TABLE

    Used to completely destroy an existing table and all its data.

    DESCRIBE (or DESC)

    Shows the structure of a table (columns, data types, etc.).

    These statements are part of the SQL Data Manipulation Language - DML.

    • SELECT: Used when you want to read (or select) your data from one or more tables.

    • INSERT: Used when you want to add (or insert) new rows of data into a table.

    • UPDATE: Used when you want to change (or update) existing data in a table.

    • : Used when you want to remove (or delete) existing rows of data from a table.

    • : Works like INSERT, but if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.

    • : Used to quickly remove all data from a table, resetting any AUTO_INCREMENT values. It is faster than DELETE without a WHERE clause for emptying a table.

    These statements are part of the SQL Transaction Control Language - TCL.

    • START TRANSACTION (or BEGIN): Used to begin a new transaction, allowing multiple SQL statements to be treated as a single atomic unit.

    • COMMIT: Used to save all changes made during the current transaction, making them permanent.

    • ROLLBACK: Used to discard all changes made during the current transaction, reverting the database to its state before the transaction began.

    This example demonstrates several of the statements in action:

    Common Query: Counting Rows

    To count the number of records in a table:

    (Note: This query would typically be run on an existing table, for example, before it or its database is dropped.)

    The first version of this article was copied, with permission, from Basic_SQL_Statements on 2012-10-05.

    This page is licensed: CC BY-SA / Gnu FDL

    Defining How Your Data Is Stored

    A MariaDB Primer
    Essential Queries Guide
    CREATE DATABASE
    -- Create a new database
    CREATE DATABASE mydb;
    
    -- Select the new database to use
    USE mydb;
    
    -- Create a new table
    CREATE TABLE mytable (
        id INT PRIMARY KEY,
        name VARCHAR(20)
    );
    
    -- Insert some data
    INSERT INTO mytable VALUES (1, 'Will');
    INSERT INTO mytable VALUES (2, 'Marry');
    INSERT INTO mytable VALUES (3, 'Dean');
    
    -- Select specific data
    SELECT id, name FROM mytable WHERE id = 1;
    
    -- Update existing data
    UPDATE mytable SET name = 'Willy' WHERE id = 1;
    
    -- Select all data to see changes
    SELECT id, name FROM mytable;
    
    -- Delete specific data
    DELETE FROM mytable WHERE id = 1;
    
    -- Select all data again
    SELECT id, name FROM mytable;
    
    -- Drop the database (removes the database and its tables)
    DROP DATABASE mydb;
    SELECT COUNT(*) FROM mytable; -- Or SELECT COUNT(1) FROM mytable;

    Manipulating Your Data

    Transactions

    A Simple Example Sequence

    spinner
    to allow the database to cache more data in memory, reducing disk I/O.
  • Controlling Behavior: You use them to toggle features on or off. Setting read_only to 1 ensures no data can be modified (useful for maintenance or replicas).

  • Enforcing Constraints: You set limits to prevent resource exhaustion. For example, max_connections prevents the server from being overwhelmed by too many simultaneous users.

  • Session Personalization: Many variables can be set at the Session level. This means you can change how the server behaves just for your current connection – like changing the sql_mode to be more or less strict – without affecting other users.

  • Status variables are read-only counters and metrics. You use them to monitor the health and activity of the server.

    • Performance Monitoring: You check status variables to see if your system tuning is working. If you see high numbers for Select_full_join, it tells you that your queries are missing indexes.

    • Health Checks: You use them to identify bottlenecks. If Aborted_connects is high, you might have network issues or a client with the wrong password attempting to connect repeatedly.

    • Resource Tracking: They tell you how much of your allocated resources are actually being used. Comparing Max_used_connections against your system variable max_connections helps you decide if you need to scale up.

    • Capacity Planning: By monitoring variables like Bytes_sent and Bytes_received over time, you can forecast when you will need to upgrade your hardware or network bandwidth.

    Feature

    System Variables

    Status Variables

    Analogy

    Steering wheel / Gas pedal

    Speedometer / Fuel gauge

    Action

    Set (change the value)

    Here is the comprehensive list of pages that document variables.

    • Server System Variables (The main list for general server configuration)

    • Server Status Variables (Real-time monitoring metrics)

    • Performance Schema System Variables

    • Aria System Variables

    • Aria Status Variables

    • InnoDB System Variables

    • MyISAM System Variables

    • Replication and Binary Log System Variables

    • Replication and Binary Log Status Variables

    • Thread Pool System and Status Variables

    • Audit Plugin Options and System Variables

    • Audit Plugin Status Variables

    • Encryption Plugin System Variables (for instance, File Key Management)

    • Full list of MariaDB options, system and status variables &#xNAN;Note: This page acts as a directory that links back to the detailed pages above.

    What you do with System Variables

    What you use Status Variables for

    Comparison at a Glance

    Pages Documenting Variables

    Core Server Variables

    Storage Engine Specific Variables

    Replication & Performance Variables

    Plugin Specific Variables

    Index / Master List

    Views are useful to separate complex processing, such as advanced JOIN operations, from the application. In some cases, VIEWs introduce performance issues, but these cases are rare.

    As for database code / SQL in applications, there are several best practices to stick to.

    Avoid SELECT * in applications; these have several bad effects, such as assuming in the application what columns are in a table, no more and no less, and in what order. This is not a good idea. In addition, selecting more columns than necessary does affect performance and may cause the optimizer to use a non-optimal path. Note that SELECT * makes two assumptions: first that it assumes which columns exist in a table, and secondly, the order in which these columns are defined. Getting any of these wrong can break things unnecessarily, and using this construct in application code makes schema changes more difficult.

    Just as in the case of SELECT *, an INSERT without column names, such as this ...

    ... is a bad idea. The proper way to write an SQL statement like this is:

    Not doing this may cause errors in the application if the table is changed, such as when columns are added or the order of the columns is changed.

    When data is returned from a SELECT statement, it is sometimes tempting to put processing of values in the SQL statement, like this:

    This is not incorrect in any way and is perfectly valid, but sometimes it is better to do this processing in the application. The best is to be consistent and the issue with this kind of construct is that it sometimes makes the SQL less readable than necessary.

    It is possible to use reserved words in names of schema objects and in the SQL itself, as here:

    And here:

    Both of these are valid constructs, but are not really recommended. The keyword order used above is likely among the most likely reserved words to use in a schema, but there are more. It is best to avoid them completely, even though quoting them makes the schema and SQL syntax valid.

    This is an issue that sometimes comes into play, where an application assumes data is processed in a particular order or in a particular way. This really should never be done in an application. One of the best examples is the ordering of rows retrieved; one should not even rely on data being returned in the order of a PRIMARY KEY or some index. Example:

    In the example, the order of the rows returned changed after the index was created, as the index can be used to fetch the data, and when the optimizer does that, it processes the index in order, which means the data is returned in the order of the index. Relying on this ordering in the application is not a good idea, though. If you require data to be returned in a particular order, then you have to use an ORDER BY clause; if you don’t, the row ordering should be treated as being undetermined.

    Another example is the LIMIT clause. When using LIMIT with a SELECT, the rows that are returned are undetermined unless an ORDER BY clause is provided. When using a LIMIT clause with an UPDATE or DELETE statement, it is even more important to understand that ordering is not fixed unless an ORDER BY statement is used. In general, I’d be careful with using the LIMIT clause for UPDATE and DELETE unless there is a good reason to do so.

    There are other assumptions than row ordering, but it is one of the most common issues.

    Following some internal standards is really helpful when it comes to building applications that can be maintained. Standardizing how to determine the data type, the column name and how to interact with the database schema is a good first step in making an application easy to maintain over time. This also helps in making application code easy to read, which is also helpful.

    There are situations where the application-level SQL gets really complex, sometimes too complex, which in turn makes the code hard to maintain. In those cases, it is sometimes useful to break up a very complex SQL SELECT into multiple statements. In particular, complex SELECT JOIN queries are troublesome in this respect. If a JOIN is not a straight equi-join but a more complex one, for example, joining of a part of a database column, say the YEAR part of a DATETIME field, then things get really complex. An alternative is sometimes to use temporary tables, which are very efficient in MariaDB, instead of a single very complex SELECT.

    • Stored procedures and functions

    • Views

    • SELECT

    • INSERT

    • \

    Object Relational Mappers (ORM)

    Stored Procedures and Functions

    INSERT INTO `orders_t` VALUES(1, ‘2025-06-01 12:00:00’);
    INSERT INTO `orders_t`(`order_id`, `order_date`)
      VALUES(1, ‘2025-06-01 12:00:00’);
    SELECT YEAR(`order_date`) AS `order_year` FROM `orders_t`;
    CREATE TABLE `order`(`order_id` INTEGER NOT NULL PRIMARY KEY);
    SELECT order_id AS `order` FROM orders_t;
    MariaDB> SELECT `order_date` FROM `orders_t`;
    +---------------------+
    | order_date          |
    +---------------------+
    | 2024-05-17 18:01:01 |
    | 2025-12-12 18:44:08 |
    | 2025-12-12 18:44:17 |
    | 2025-09-09 14:57:47 |
    +---------------------+
    4 rows in set (0.000 sec)
    
    MariaDB> ALTER TABLE `orders_t` ADD KEY(`order_date`);
    Query OK, 0 rows affected (0.034 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    MariaDB> SELECT `order_date` FROM `orders_t`;
    +---------------------+
    | order_date          |
    +---------------------+
    | 2024-05-17 18:01:01 |
    | 2025-09-09 14:57:47 |
    | 2025-12-12 18:44:08 |
    | 2025-12-12 18:44:17 |
    +---------------------+
    4 rows in set (0.003 sec)

    Views

    Application Code

    SELECT *

    INSERT Without Column Names

    Processing of Column Data

    Use of Reserved Words in the Schema

    Relying on Nonexplicit Assumptions

    Code and Schema Standardization

    Complex SQL

    See Also

    OPTIMIZE TABLE
  • ANALYZE TABLE

  • REPAIR TABLE

  • To target one or more specific partitions rather than the entire table, use the ALTER TABLE extensions listed below. In the SQL syntaxes below, partition_names is a comma-separated list of partitions, like p0, p1, p2.

    Use this to defragment a partition. This operation drops all records in the partition and re-inserts them:

    If you have deleted many rows or modified variable-length columns (such as VARCHAR, BLOB, or TEXT), use this statement to reclaim unused space and defragment the data file:

    Use this to read and store the key distributions for specific partitions:

    Use this to fix corrupted partitions:

    You can verify the integrity of data and indexes within a partition:

    To remove all rows from specific partitions while keeping the table structure, use the TRUNCATE PARTITION clause:

    Reorganizing partitions isn't just maintenance, but it can help with making future maintenance easier. Use the following statement to change the structure of existing partitions without losing data. This is particularly useful for splitting a partition that contains a MAXVALUE range into a new specific range and a new MAXVALUE partition. Use the following syntax:

    Example: If you have a partition p_future defined as VALUES LESS THAN MAXVALUE, you can split it to add a specific range for the year 2026:

    When managing partitioned tables, follow these guidelines to ensure optimal performance and maintainability.

    Partitioning is most effective for tables containing time-series data where you periodically remove old records.

    • Efficient Deletion: Use DROP PARTITION instead of DELETE to remove expired data. This is a metadata operation and is significantly faster than row-by-row deletion.

    • The Future Partition: When using RANGE partitioning, define a "future" partition using VALUES LESS THAN MAXVALUE. To add a new specific range, use REORGANIZE PARTITION to split the "future" partition into a new range and a new MAXVALUE partition. See for the syntax.

    • The Start Partition: Consider creating a small, empty "start" partition (for example, VALUES LESS THAN (0)) to catch NULL values or invalid data. Because the partition pruner often scans the first partition by default, keeping it empty improves query efficiency.

    • Table Size: Partitioning generally provides noticeable benefits only for tables with more than one million rows.

    • Partition Limits: Aim to keep the number of partitions below 50. While MariaDB supports up to 8192 partitions, high partition counts can increase the time required for the server to open the table or perform status checks.

    • Index Efficiency: Partitioning is not a substitute for proper indexing. Point queries (finding a single row) are often just as fast with a proper index on a non-partitioned table.

    This page is licensed: CC BY-SA / Gnu FDL

    Maintenance Instructions

    Table-Level Maintenance

    ALTER TABLE table_name REBUILD PARTITION partition_names
    ALTER TABLE table_name OPTIMIZE PARTITION partition_names
    ALTER TABLE table_name ANALYZE PARTITION partition_names
    ALTER TABLE table_name REPAIR PARTITION partition_names
    ALTER TABLE table_name CHECK PARTITION partition_names
    ALTER TABLE table_name TRUNCATE PARTITION partition_names
    ALTER TABLE table_name REORGANIZE PARTITION partition_names INTO (PARTITION partition_definition, ...)
    ALTER TABLE tbl REORGANIZE PARTITION p_future INTO (PARTITION p_2026 VALUES LESS THAN (2027), PARTITION p_future VALUES LESS THAN MAXVALUE)

    Partition-Specific Operations

    For an operation to be performed on all partitions, you can use the ALL keyword instead of specifying all the partitions in a comma-separated list. Example:

    Rebuilding Partitions

    Optimizing Partitions

    Some storage engines, including InnoDB, do not support per-partition optimization. When you run OPTIMIZE PARTITION on an InnoDB table, MariaDB rebuilds and analyzes the entire table instead.

    Analyzing Partitions

    Repairing Partitions

    Checking Partitions

    Truncating Partitions

    Reorganizing Partitions

    Best Practices and Considerations

    Managing Time-Series Data

    Performance and Scale

    spinner

    If the source database server is a replica of the desired primary, then we should add the --slave-info option, and possibly the --safe-slave-backup option. For example:

    And then we would prepare the backup as you normally would. For example:

    Once the backup is done and prepared, we can copy it to the new replica. For example:

    At this point, we can restore the backup to the datadir, as you normally would. For example:

    And adjusting file permissions, if necessary:

    Before the new replica can begin replicating from the primary, we need to create a user account on the primary that the replica can use to connect, and we need to grant the user account the REPLICATION SLAVE privilege. For example:

    Before we start the server on the new replica, we need to configure it. At the very least, we need to ensure that it has a unique server_id value. We also need to make sure other replication settings are what we want them to be, such as the various GTID system variables, if those apply in the specific environment.

    Once configuration is done, we can start the MariaDB Server process on the new replica.

    At this point, we need to get the replication coordinates of the primary from the original backup directory.

    If we took the backup on the primary, then the coordinates are in the xtrabackup_binlog_info file. If we took the backup on another replica and if we provided the --slave-info option, then the coordinates are in the file xtrabackup_slave_info file.

    mariadb-backup dumps replication coordinates in two forms: GTID coordinates and binary log file and position coordinates, like the ones you would normally see from SHOW MASTER STATUS output. We can choose which set of coordinates we would like to use to set up replication.

    For example:

    Regardless of the coordinates we use, we will have to set up the primary connection using CHANGE MASTER TO and then start the replication threads with START SLAVE.

    If we want to use GTIDs, then we will have to first set gtid_slave_pos to the GTID coordinates that we pulled from either the xtrabackup_binlog_info file or the xtrabackup_slave_info file in the backup directory. For example:

    And then we would set MASTER_USE_GTID=slave_pos in the CHANGE MASTER TO statement. For example:

    If we want to use the binary log file and position coordinates, then we would set MASTER_LOG_FILE and MASTER_LOG_POS in the CHANGE MASTER TO statement to the file and position coordinates that we pulled; either the xtrabackup_binlog_info file or the xtrabackup_slave_info file in the backup directory, depending on whether the backup was taken from the primary or from a replica of the primary. For example:

    We should be done setting up the replica now, so we should check its status with SHOW SLAVE STATUS. For example:

    This page is licensed: CC BY-SA / Gnu FDL

    The terms master and slave have historically been used in replication, and MariaDB has begun the process of adding primary and replica synonyms. The old terms will continue to be used to maintain backward compatibility - see MDEV-18777 to follow progress on this effort.

    mariadb-backup was previously called mariabackup.

    For a complete list of mariadb-backup options, see this page.

    For a detailed description of mariadb-backup functionality, see this page.

    Back up the Database and Prepare it

    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    $ mariadb-backup --backup \
       --slave-info --safe-slave-backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    $ mariadb-backup --prepare \
       --target-dir=/var/mariadb/backup/
    $ rsync -avP /var/mariadb/backup dbserver2:/var/mariadb/backup
    $ mariadb-backup --copy-back \
       --target-dir=/var/mariadb/backup/
    $ chown -R mysql:mysql /var/lib/mysql/
    CREATE USER 'repl'@'dbserver2' IDENTIFIED BY 'password';
    GRANT REPLICATION SLAVE ON *.*  TO 'repl'@'dbserver2';
    mariadb-bin.000096 568 0-1-2
    $ cat xtrabackup_binlog_info
    mariadb-bin.000096 568 0-1-2
    SET GLOBAL gtid_slave_pos = "0-1-2";
    CHANGE MASTER TO 
       MASTER_HOST="dbserver1", 
       MASTER_PORT=3306, 
       MASTER_USER="repl",  
       MASTER_PASSWORD="password", 
       MASTER_USE_GTID=slave_pos;
    START SLAVE;
    CHANGE MASTER TO 
       MASTER_HOST="dbserver1", 
       MASTER_PORT=3306, 
       MASTER_USER="repl",  
       MASTER_PASSWORD="password", 
       MASTER_LOG_FILE='mariadb-bin.000096',
       MASTER_LOG_POS=568;
    START SLAVE;
    SHOW SLAVE STATUS\G

    Copy the Backup to the New Replica

    Restore the Backup on the New Replica

    Create a Replication User on the Primary

    Configure the New Replica

    Start Replication on the New Replica

    GTIDs

    File and Position

    Check the Status of the New Replica

    spinner
    The
    FETCH GROUP NEXT ROW
    instruction inside the loop
  • Oracle PL/SQL compatibility using SQL/PL is provided

  • Stored aggregate functions were a project by Varun Gupta.

    First a simplified example:

    A non-trivial example that cannot easily be rewritten using existing functions:

    This uses the same marks table as created above.

    • Stored Function Overview

    • CREATE FUNCTION

    • SHOW CREATE FUNCTION

    • DROP FUNCTION

    This page is licensed: CC BY-SA / Gnu FDL

    Aggregate functions
    CREATE FUNCTION
    CREATE AGGREGATE FUNCTION function_name (parameters) RETURNS return_type
    BEGIN
          ALL types of declarations
          DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN return_val;
          LOOP
               FETCH GROUP NEXT ROW; // fetches next row FROM TABLE
               other instructions
          END LOOP;
    END
    SET sql_mode=Oracle;
    DELIMITER //
    
    CREATE AGGREGATE FUNCTION function_name (parameters) RETURN return_type
       declarations
    BEGIN
       LOOP
          FETCH GROUP NEXT ROW; -- fetches next row from table
          -- other instructions
    
       END LOOP;
    EXCEPTION
       WHEN NO_DATA_FOUND THEN
          RETURN return_val;
    END //
    
    DELIMITER ;
    CREATE TABLE marks(stud_id INT, grade_count INT);
    
    INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8);
    
    SELECT * FROM marks;
    +---------+-------------+
    | stud_id | grade_count |
    +---------+-------------+
    |       1 |           6 |
    |       2 |           4 |
    |       3 |           7 |
    |       4 |           5 |
    |       5 |           8 |
    +---------+-------------+
    
    DELIMITER //
    CREATE AGGREGATE FUNCTION IF NOT EXISTS aggregate_count(x INT) RETURNS INT
    BEGIN
     DECLARE count_students INT DEFAULT 0;
     DECLARE CONTINUE HANDLER FOR NOT FOUND
     RETURN count_students;
          LOOP
              FETCH GROUP NEXT ROW;
              IF x  THEN
                SET count_students = count_students+1;
              END IF;
          END LOOP;
    END //
    DELIMITER ;
    DELIMITER //
    CREATE AGGREGATE FUNCTION medi_int(x INT) RETURNS DOUBLE
    BEGIN
      DECLARE CONTINUE HANDLER FOR NOT FOUND
        BEGIN
          DECLARE res DOUBLE;
          DECLARE cnt INT DEFAULT (SELECT COUNT(*) FROM tt);
          DECLARE lim INT DEFAULT (cnt-1) DIV 2;
          IF cnt % 2 = 0 THEN
            SET res = (SELECT AVG(a) FROM (SELECT a FROM tt ORDER BY a LIMIT lim,2) ttt);
          ELSE
            SET res = (SELECT a FROM tt ORDER BY a LIMIT lim,1);
          END IF;
          DROP TEMPORARY TABLE tt;
          RETURN res;
        END;
      CREATE TEMPORARY TABLE tt (a INT);
      LOOP
        FETCH GROUP NEXT ROW;
        INSERT INTO tt VALUES (x);
      END LOOP;
    END //
    DELIMITER ;
    SET sql_mode=Oracle;
    DELIMITER //
    
    CREATE AGGREGATE FUNCTION aggregate_count(x INT) RETURN INT AS count_students INT DEFAULT 0;
    BEGIN
       LOOP
          FETCH GROUP NEXT ROW;
          IF x  THEN
            SET count_students := count_students+1;
          END IF;
       END LOOP;
    EXCEPTION
       WHEN NO_DATA_FOUND THEN
          RETURN count_students;
    END aggregate_count //
    DELIMITER ;
    
    SELECT aggregate_count(stud_id) FROM marks;

    Standard Syntax

    Using SQL/PL

    Examples

    SQL/PL Example

    See Also

    spinner
    X
    , which is simply set to 42, and this is the result returned.

    Of course, a function that doesn't take any arguments is of little use. Here's a more complex example:

    This function takes an argument, price which is defined as a DECIMAL, and returns an INT.

    Take a look at the CREATE FUNCTION page for more details.

    It is also possible to create stored aggregate functions.

    To find which stored functions are running on the server, use SHOW FUNCTION STATUS:

    Alternatively, query the routines table in the INFORMATION_SCHEMA database directly:

    To find out what the stored function does, use SHOW CREATE FUNCTION:

    To drop a stored function, use the DROP FUNCTION statement.

    To change the characteristics of a stored function, use ALTER FUNCTION. Note that you cannot change the parameters or body of a stored function using this statement; to make such changes, you must drop and re-create the function using DROP FUNCTION and CREATE FUNCTION.

    See the article Stored Routine Privileges.

    • CREATE FUNCTION

    • SHOW CREATE FUNCTION

    • DROP FUNCTION

    • Stored Routine Privileges

    • .

    This page is licensed: CC BY-SA / Gnu FDL

    DELIMITER //
    
    CREATE FUNCTION FortyTwo() RETURNS TINYINT DETERMINISTIC
    BEGIN
     DECLARE x TINYINT;
     SET x = 42;
     RETURN x;
    END 
    
    //
    
    DELIMITER ;

    Creating Stored Functions

    Delimiters in the mariadb client
    BEGIN and END
    SELECT FortyTwo();
    +------------+
    | FortyTwo() |
    +------------+
    |         42 |
    +------------+
    DELIMITER //
    CREATE FUNCTION VatCents(price DECIMAL(10,2)) RETURNS INT DETERMINISTIC
    BEGIN
     DECLARE x INT;
     SET x = price * 114;
     RETURN x;
    END //
    Query OK, 0 rows affected (0.04 sec)
    DELIMITER ;
    SHOW FUNCTION STATUS\G
    *************************** 1. row ***************************
                      Db: test
                    Name: VatCents
                    Type: FUNCTION
                 Definer: root@localhost
                Modified: 2013-06-01 12:40:31
                 Created: 2013-06-01 12:40:31
           Security_type: DEFINER
                 Comment: 
    character_set_client: utf8
    collation_connection: utf8_general_ci
      Database Collation: latin1_swedish_ci
    1 row in set (0.00 sec)
    SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE
      ROUTINE_TYPE='FUNCTION';
    +--------------+
    | ROUTINE_NAME |
    +--------------+
    | VatCents     |
    +--------------+
    SHOW CREATE FUNCTION VatCents\G
    *************************** 1. row ***************************
                Function: VatCents
                sql_mode: 
         Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION `VatCents`(price DECIMAL(10,2)) RETURNS int(11)
        DETERMINISTIC
    BEGIN
     DECLARE x INT;
     SET x = price * 114;
     RETURN x;
    END
    character_set_client: utf8
    collation_connection: utf8_general_ci
      Database Collation: latin1_swedish_ci
    DROP FUNCTION FortyTwo;

    Stored Function Listings and Definitions

    Dropping and Updating Stored Functions

    Permissions in Stored Functions

    See Also

    spinner
    or a non-unique key. However, it has a limitation: it is not possible to insert a value which is lower than the next
    AUTO_INCREMENT
    value.

    Although the plugin's shared library is distributed with MariaDB by default, the plugin is not actually installed by MariaDB by default. There are two methods that can be used to install the plugin with MariaDB.

    The first method can be used to install the plugin without restarting the server. You can install the plugin dynamically by executing INSTALL SONAME or INSTALL PLUGIN:

    The second method can be used to tell the server to load the plugin when it starts up. The plugin can be installed this way by providing the --plugin-load or the --plugin-load-add options. This can be specified as a command-line argument to mysqld or it can be specified in a relevant server option group in an option file:

    You can uninstall the plugin dynamically by executing UNINSTALL SONAME or UNINSTALL PLUGIN:

    If you installed the plugin by providing the --plugin-load or the --plugin-load-add options in a relevant server option group in an option file, then those options should be removed to prevent the plugin from being loaded the next time the server is restarted.

    • Supports INSERT and SELECT, but not DELETE, UPDATE or REPLACE.

    • Data is compressed with zlib as it is inserted, making it very small.

    • Data is slow the select, as it needs to be uncompressed, and, besides the query cache, there is no cache.

    • Supports AUTO_INCREMENT (since MariaDB/MySQL 5.1.6), which can be a unique or a non-unique index.

    • Since MariaDB/MySQL 5.1.6, selects scan past BLOB columns unless they are specifically requested, making these queries much more efficient.

    • Does not support data types.

    • Does not support .

    • Does not support foreign keys.

    • Does not support .

    • No storage limit.

    • Supports row locking.

    • Supports , and the server can access ARCHIVE tables even if the corresponding .frm file is missing.

    • and can be used to compress the table in its entirety, resulting in slightly better compression.

    • With MariaDB, it is possible to upgrade from the MySQL 5.0 format without having to dump the tables.

    • is supported.

    • Running many SELECTs during the insertions can deteriorate the compression, unless only multi-rows INSERTs and INSERT DELAYED are used.

    AUTO_INCREMENT
    INSTALL SONAME 'ha_archive';
    [mariadb]
    ...
    plugin_load_add = ha_archive
    UNINSTALL SONAME 'ha_archive';

    Installing the Plugin

    Uninstalling the Plugin

    Characteristics

    , looking for InnoDB tablespaces, load the tablespaces (basically, it is an “open” in InnoDB sense)
  • If --lock-ddl-per-table is used:

    • Do MDL locks, for InnoDB tablespaces that we want to copy. This is to ensure that there are no ALTER, RENAME , TRUNCATE or DROP TABLE on any of the tables that we want to copy.

    • This is implemented with:

    • If lock-ddl-per-table is not done, then mariadb-backup would have to know all tables that were created or altered during the backup. See MDEV-16791.

    Start a dedicated thread in mariadb-backup to copy InnoDB redo log (ib_logfile*).

    • This is needed to record all changes done while the backup is running. (The redo log logically is a single circular file, split into innodb_log_files_in_group files.)

    • The log is also used to see detect if any truncate or online alter tables are used.

    • The assumption is that the copy thread are able to keep up with server. It should always be able keep up, if the redo log is big enough.

    • Copy all selected tablespaces, file by file, in dedicated threads in mariadb-backup without involving the mysqld server.

    • This is special “careful” copy, it looks for page-level consistency by checking the checksum.

    • The files are not point-in-time consistent as data may change during copy.

    • The idea is that InnoDB recovery would make it point-in-time consistent.

    • Execute FLUSH TABLE WITH READ LOCK. This is default, but may be omitted with the -–no-lock parameter. The reason why FLUSH is needed is to ensure that all tables are in a consistent state at the exact same point in time, independent of storage engine.

    • If --lock-ddl-per-table is used and there is a user query waiting for MDL, the user query are killed to resolve a deadlock. Note that these are only queries of type ALTER, DROP, TRUNCATE or RENAME TABLE. ()

    • Copy .frm, MyISAM, Aria and other storage engine files.

    • If MyRocks is used, create rocksdb checkpoint via the set rocksdb_create_checkpoint=$rocksdb_data_dir/mariadb-backup_rocksdb_checkpoint command. The result of it is a directory with hardlinks to MyRocks files. Copy the checkpoint directory to the backup (or create hardlinks in backup directory is on the same partition as data directory). Remove the checkpoint directory.

    • Copy tables that were created while the backup was running and do rename files that were changed during backup (since ).

    • Copy the rest of InnoDB redo log, stop redo-log-copy thread.

    • Write some metadata info (binlog position).

    • If FLUSH TABLE WITH READ LOCK was done:

      • execute: UNLOCK TABLES

    • If --lock-ddl-per-table was done:

      • execute COMMIT

    • If log tables exists:

      • Take MDL lock for log tables

      • Copy part of log tables that wasn't copied before

      • Unlock log tables

    • If FLUSH TABLE WITH READ LOCK is not used, only InnoDB tables are consistent (not the privilege tables in the mysql database or the binary log). The backup point depends on the content of the redo log within the backup itself.

    This page is licensed: CC BY-SA / Gnu FDL

    mariadb-backup was previously called mariabackup.

    Execution Stages

    Initialization Phase

    BEGIN
    FOR EACH affected TABLE
    SELECT 1 FROM <TABLE> LIMIT 0

    Redo Log Handling

    Copy-phase for InnoDB Tablespaces

    Create a Consistent Backup Point

    Last Copy Phase

    Release Locks

    Handle Log Tables (TODO)

    Notes

    spinner
    CREATE USER 'backup_replica'@'replica_ip_or_hostname' IDENTIFIED BY 'strong_password';
    GRANT REPLICATION SLAVE ON *.* TO 'backup_replica'@'replica_ip_or_hostname';
    SHOW GLOBAL VARIABLES LIKE 'gtid_current_pos';
    SET GLOBAL gtid_slave_pos='<gtid_value_from_primary>';
    CHANGE MASTER TO
       MASTER_HOST='primary_domain_or_ip',
       MASTER_PORT=3306,
       MASTER_USER='backup_replica',
       MASTER_PASSWORD='strong_password',
       MASTER_SSL=1,
       MASTER_USE_GTID=slave_pos;
    START REPLICA;
    SHOW REPLICA STATUS \G

    Setting Up a Dedicated Backup Replica

    1. Create a User for Replication

    2. Obtain the GTID Position

    3. Configure the GTID Position on the Replica

    4. Configure Replication

    5. Start Replication

    6. Check Replication Status

    See Also

    Replication and Foreign Keys
    Replication
    Backup & Restore
    MDEV-18777
    spinner

    Joining Tables with JOIN Clauses

    This guide introduces the different types of JOINs (INNER, LEFT, RIGHT, CROSS) and demonstrates how to combine data from multiple tables.

    This guide offers a simple, hands-on introduction to three basic JOIN types in MariaDB: INNER JOIN, CROSS JOIN, and LEFT JOIN. Use these examples to understand how different joins combine data from multiple tables based on specified conditions.

    Setup: Example Tables and Data

    First, create and populate two simple tables, t1 and t2, to use in the JOIN examples:

    CREATE TABLE t1 ( a INT );
    CREATE TABLE t2 ( b INT );
    
    INSERT INTO t1 VALUES (1), (2), (3);
    INSERT INTO t2 VALUES (2), (4);

    JOIN Examples and Output

    Below are examples of different JOIN types using the tables t1 and t2.

    An INNER JOIN produces a result set containing only rows that have a match in both tables for the specified join condition(s).

    Output:

    Explanation: Only the row where t1.a (value 2) matches t2.b (value 2) is returned.

    A CROSS JOIN produces a result set in which every row from the first table is joined to every row in the second table. This is also known as a Cartesian product.

    Output:

    Explanation: Each of the 3 rows in t1 is combined with each of the 2 rows in t2, resulting in 3 * 2 = 6 rows. Note: In MariaDB, the CROSS keyword can often be omitted if no ON clause is present (e.g., SELECT * FROM t1 JOIN t2; or SELECT * FROM t1, t2; would also produce a Cartesian product).

    A LEFT JOIN (or LEFT OUTER JOIN) produces a result set with all rows from the "left" table (t1 in this case). If a match is found in the "right" table (t2), the corresponding columns from the right table are included. If no match is found, these columns are filled with NULL.

    Output:

    Explanation: All rows from t1 are present. For t1.a = 1 and t1.a = 3, there are no matching t2.b values, so b is NULL. For t1.a = 2, a match is found (t2.b = 2), so b is 2.

    Starting with MariaDB 12.3, multiple independent LEFT JOIN operations can be reordered by the optimizer for better performance if the flag is enabled in . It is also recommended to set optimizer_prune_level=0 to prevent heuristic pruning from eliminating optimal join orders.

    A RIGHT JOIN (or RIGHT OUTER JOIN) produces a result set with all rows from the "right" table (t2 in this case). If a match is found in the "left" table (t1), the corresponding columns from the left table are included. If no match is found, these columns are filled with NULL.

    Output:

    This example uses a LEFT JOIN but with t2 as the left table. This effectively demonstrates how a RIGHT JOIN would behave if t1 were the left table and t2 the right. A RIGHT JOIN includes all rows from the "right" table and NULLs for non-matching "left" table columns.

    Output:

    Explanation: All rows from t2 are present. For t2.b = 2, a match is found (t1.a = 2), so a is 2. For t2.b = 4, there is no matching t1.a value, so a is NULL.

    The first two SELECT statements (INNER JOIN and CROSS JOIN) are sometimes written using an older, implicit join syntax:

    • Implicit INNER JOIN:

      This is equivalent to SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.b;.

    • Implicit CROSS JOIN (Cartesian Product):

      This is equivalent to SELECT * FROM t1 CROSS JOIN t2;.

    While this syntax works, the explicit JOIN syntax (INNER JOIN, LEFT JOIN, etc.) with an ON clause is generally preferred for clarity and to better distinguish join conditions from filtering conditions (WHERE clause).

    • INNER JOIN: Returns rows only when there is a match in both tables based on the join condition.

    • CROSS JOIN: Returns the Cartesian product of the two tables (all possible combinations of rows).

    • LEFT JOIN

    JOIN clauses can be concatenated (chained) to retrieve results from three or more tables by progressively joining them.

    The initial version of this article was copied, with permission, from on 2012-10-05.

    This page is licensed: CC BY-SA / Gnu FDL

    Basic SQL Debugging Guide

    This guide offers conventions and practical tips for designing SQL queries that are easier to read, understand, and debug.

    Designing Queries

    Following a few conventions makes finding errors in queries a lot easier, especially when you ask for help from people who might know SQL, but know nothing about your particular schema. A query easy to read is a query easy to debug. Use whitespace to group clauses within the query. Choose good table and field aliases to add clarity, not confusion. Choose the syntax that supports the query's meaning.

    Using Whitespace

    A query hard to read is a query hard to debug. White space is free. New lines and indentation make queries easy to read, particularly when constructing a query inside a scripting language, where variables are interspersed throughout the query.

    There is a syntax error in the following. How fast can you find it?

    SELECT u.id, u.name, alliance.ally FROM users u JOIN alliance ON
    (u.id=alliance.userId) JOIN team ON (alliance.teamId=team.teamId
    WHERE team.teamName='Legionnaires' AND u.online=1 AND ((u.subscription='paid'
    AND u.paymentStatus='current') OR u.subscription='free') ORDER BY u.name;

    Here's the same query, with correct use of whitespace. Can you find the error faster?

    SELECT
        u.id
        , u.name
        , alliance.ally
    FROM
        users u
        JOIN alliance ON (u.id = alliance.userId)
        JOIN team ON (alliance.teamId = team.teamId
    WHERE
        team.teamName = 'Legionnaires'
        AND u.online = 1
        AND (
            (u.subscription = 'paid' AND u.paymentStatus = 'current')
            OR
            u.subscription = 'free'
        )
    ORDER BY
        u.name;

    Even if you don't know SQL, you might still have caught the missing ')' following team.teamId.

    The exact formatting style you use isn't so important. You might like commas in the select list to follow expressions, rather than precede them. You might indent with tabs or with spaces. Adherence to some particular form is not important. Legibility is the only goal.

    Aliases allow you to rename tables and fields for use within a query. This can be handy when the original names are very long, and is required for self joins and certain subqueries. However, poorly chosen aliases can make a query harder to debug, rather than easier. Aliases should reflect the original table name, not an arbitrary string.

    Bad:

    As the list of joined tables and the WHERE clause grow, it becomes necessary to repeatedly look back to the top of the query to see to which table any given alias refers.

    Better:

    Each alias is just a little longer, but the table initials give enough clues that anyone familiar with the database only need see the full table name once, and can generally remember which table goes with which alias while reading the rest of the query.

    The manual warns against using the JOIN condition (that is, the ON clause) for restricting rows. Some queries, particularly those using implicit joins, take the opposite extreme - all join conditions are moved to the WHERE clause. In consequence, the table relationships are mixed with the business logic.

    Bad:

    Without digging through the WHERE clause, it is impossible to say what links the two tables.

    Better:

    The relation between the tables is immediately obvious. The WHERE clause is left to limit rows in the result set.

    Compliance with such a restriction negates the use of the comma operator to join tables. It is a small price to pay. Queries should be written using the explicit JOIN keyword anyway, and the two should never be mixed (unless you like rewriting all your queries every time a new version changes operator precedence).

    Syntax errors are among the easiest problems to solve. MariaDB provides an error message showing the exact point where the parser became confused. Check the query, including a few words before the phrase shown in the error message. Most syntax and parsing errors are obvious after a second look, but some are more elusive, especially when the error text seems empty, points to a valid keyword, or seems to error on syntax that appears exactly correct.

    Most syntax errors are easy to interpret. The error generally details the exact source of the trouble. A careful look at the query, with the error message in mind, often reveals an obvious mistake, such as misspelled field names, a missing 'AND', or an extra closing parenthesis. Sometimes the error is a little less helpful. A frequent, less-than-helpful message:

    The empty ' ' can be disheartening. Clearly there is an error, but where? A good place to look is at the end of the query. The ' ' suggests that the parser reached the end of the statement while still expecting some syntax token to appear.

    Check for missing closers, such as ' and ):

    Look for incomplete clauses, often indicated by an exposed comma:

    MariaDB allows table and field names and aliases that are also . To prevent ambiguity, such names must be enclosed in backticks (`):

    If the syntax error is shown near one of your identifiers, check if it appears on the .

    A text editor with color highlighting for SQL syntax helps to find these errors. When you enter a field name, and it shows up in the same color as the SELECT keyword, you know something is amiss. Some common culprits:

    • DESC is a common abbreviation for "description" fields. It means "descending" in a MariaDB ORDER clause.

    • DATE, TIME, and TIMESTAMP are all common field names. They are also field types.

    • ORDER appears in sales applications. MariaDB uses it to specify sorting for results.

    Some keywords are so common that MariaDB makes a special allowance to use them unquoted. My advice: don't. If it's a keyword, quote it.

    As MariaDB adds new features, the syntax must change to support them. Most of the time, old syntax will work in newer versions of MariaDB. One notable exception is the change in precedence of the comma operator relative to the JOIN keyword in version 5.0. A query that used to work, such as

    will now fail.

    More common, however, is an attempt to use new syntax in an old version. Web hosting companies are notoriously slow to upgrade MariaDB, and you may find yourself using a version several years out of date. The result can be very frustrating when a query that executes flawlessly on your own workstation, running a recent installation, fails completely in your production environment.

    This query fails in any version of MySQL prior to 4.1, when subqueries were added to the server:

    This query fails in some early versions of MySQL, because the JOIN syntax did not originally allow an ON clause:

    Always check the installed version of MariaDB, and read the section of the manual relevant for that version. The manual usually indicates exactly when particular syntax became available for use.

    The initial version of this article was copied, with permission, from on 2012-10-05.

    This page is licensed: CC BY-SA / Gnu FDL

    Incremental Backup and Restore (mariadb-backup)

    Complete mariadb-backup incremental guide: --backup/--prepare syntax, LSN mariadb_backup_checkpoints, --incremental-basedir, and --copy-back/--move-back restore.

    mariadb-backup was previously called mariabackup.

    When using mariadb-backup, you have the option of performing a full or incremental backup. Full backups create a complete copy in an empty directory while incremental backups update a previous backup with new data. This page documents incremental backups.

    InnoDB pages contain log sequence numbers, or LSN's. Whenever you modify a row on any InnoDB table on the database, the storage engine increments this number. When performing an incremental backup, mariadb-backup checks the most recent LSN for the backup against the LSN's contained in the database. It then updates any of the backup files that have fallen behind.

    For a complete list of mariadb-backup options, .

    For a detailed description of mariadb-backup functionality, .

    Backing up the Database Server

    In order to take an incremental backup, you first need to take a full backup. In order to back up the database, you need to run mariadb-backup with the --backup option to tell it to perform a backup and with the --target-dir option to tell it where to place the backup files. When taking a full backup, the target directory must be empty or it must not exist.

    To take a backup, run the following command:

    This backs up all databases into the target directory /var/mariadb/backup. If you look in that directory at the mariadb_backup_checkpoints file, you can see the LSN data provided by InnoDB.

    For example:

    Once you have created a full backup on your system, you can also back up the incremental changes as often as you would like.

    In order to perform an incremental backup, you need to run mariadb-backup with the --backup option to tell it to perform a backup and with the --target-dir option to tell it where to place the incremental changes. The target directory must be empty. You also need to run it with the --incremental-basedir option to tell it the path to the full backup taken above. For example:

    This command creates a series of delta files that store the incremental changes in /var/mariadb/inc1. You can find a similar mariadb_backup_checkpoints file in this directory, with the updated LSN values.

    For example:

    To perform additional incremental backups, you can then use the target directory of the previous incremental backup as the incremental base directory of the next incremental backup. For example:

    Alternatively, you can use the backup history table to manage your backup chain. This allows you to reference the previous backup by a logical name instead of a directory path.

    1. Create the Base Backup: Take a full backup using the --history option.

    2. Create the Incremental Backup: Use --incremental-history-name to specify the base backup's name. It is recommended to use --history again to record this new incremental backup.

    When using --stream, for instance for compression or encryption using external tools, the mariadb_backup_checkpoints file containing the information where to continue from on the next incremental backup will also be part of the compressed/encrypted backup file, and so not directly accessible by default.

    A directory containing an extra copy of the file can be created using the --extra-lsndir=... option though, and this directory can then be passed to the next incremental backup --incremental-basedir=..., for example:

    Following the above steps, you have three backups in /var/mariadb: The first is a full backup, the others are increments on this first backup. In order to restore a backup to the database, you first need to apply the incremental backups to the base full backup. This is done using the --prepare command option.

    Perform the following process:

    First, prepare the base backup:

    Running this command brings the base full backup, that is, /var/mariadb/backup, into sync with the changes contained in the InnoDB redo log collected while the backup was taken.

    Then, apply the incremental changes to the base full backup:

    Running this command brings the base full backup, that is, /var/mariadb/backup, into sync with the changes contained in the first incremental backup.

    For each remaining incremental backup, repeat the last step to bring the base full backup into sync with the changes contained in that incremental backup.

    Once you've applied all incremental backups to the base, you can restore the backup using either the --copy-back or the --move-back options. The --copy-back option allows you to keep the original backup files. The --move-back option actually moves the backup files to the datadir, so the original backup files are lost.

    • First, .

    • Then, ensure that the datadir is empty.

    • Then, run mariadb-backup with one of the options mentioned above:

    • Then, you may need to fix the file permissions.

    When mariadb-backup restores a database, it preserves the file and directory privileges of the backup. However, it writes the files to disk as the user and group restoring the database. As such, after restoring a backup, you may need to adjust the owner of the data directory to match the user and group for the MariaDB Server, typically mysql for both. For example, to recursively change ownership of the files to the mysql user and group, you could execute:

    • Finally, .

    This page is licensed: CC BY-SA / Gnu FDL

    Partial Backup and Restore (mariadb-backup)

    Back up specific databases or tables. This guide explains how to filter your backup to include only the data you need.

    mariadb-backup was previously called mariabackup.

    When using mariadb-backup, you have the option of performing partial backups. Partial backups allow you to choose which databases or tables to backup, as long as the table or partition involved is in an InnoDB file-per-table tablespace.This page documents how to perform partial backups.

    For a complete list of mariadb-backup options, .

    For a detailed description of mariadb-backup functionality, .

    Backing up the Database Server

    Just like with full backups, in order to back up the database, you need to run mariadb-backup with the --backup option to tell it to perform a backup and with the --target-dir option to tell it where to place the backup files. The target directory must be empty or not exist.

    For a partial backup, there are a few other arguments that you can provide as well:

    • To tell it which databases to backup, you can provide the --databases option.

    • To tell it which databases to exclude from the backup, you can provide the --databases-exclude option.

    • To tell it to check a file for the databases to backup, you can provide the --databases-file option.

    • To tell it which tables to back up, you can use .

    • To tell it which tables to exclude from the backup, you can provide the --tables-exclude option.

    • To tell it to check a file for specific tables to backup, you can provide the --tables-file option.

    The non-file partial backup options support regex in the database and table names.

    For example, to take a backup of any database that starts with the string app1_ and any table in those databases that start with the string tab_, run the following command:

    You can use the --history option with a partial backup to log the operation in the history table for auditing purposes.

    The time the backup takes depends on the size of the databases or tables you're backing up. You can cancel the backup if you need to, as the backup process does not modify the database.

    mariadb-backup writes the backup files to the target directory. If the target directory doesn't exist, then it creates it. If the target directory exists and contains files, then it raises an error and aborts.

    Just like with full backups, the data files that mariadb-backup creates in the target directory are not point-in-time consistent, given that the data files are copied at different times during the backup operation. If you try to restore from these files, InnoDB notices the inconsistencies and crashes to protect you from corruption. In fact, for partial backups, the backup is not even a completely functional MariaDB data directory, so InnoDB would raise more errors than it would for full backups. This point will also be very important to keep in mind during the restore process.

    Before you can restore from a backup, you first need to prepare it to make the data files consistent. You can do so with the --prepare command option.

    Partial backups rely on InnoDB's transportable tablespaces. For MariaDB to import tablespaces like these, InnoDB looks for a file with a .cfg extension. For mariadb-backup to create these files, you also need to add the --export option during the prepare step.

    For example, you might execute the following command:

    If this operation completes without error, then the backup is ready to be restored.

    mariadb-backup did not support the --export option. See about that. This means that mariadb-backup could not create .cfg files for InnoDB file-per-table tablespaces during the --prepare stage. You can still import file-per-table tablespaces without the .cfg files in many cases, so it may still be possible in those versions to restore partial backups or to restore individual tables and partitions with just the .ibd files. If you have a full backup and you need to create .cfg files for InnoDB file-per-table tablespaces, then you can do so by preparing the backup as usual without the --export option, and then restoring the backup, and then starting the server. At that point, you can use the server's built-in features to copy the transportable tablespaces.

    The restore process for partial backups is quite different than the process for full backups. A partial backup is not a completely functional data directory. The data dictionary in the InnoDB system tablespace will still contain entries for the databases and tables that were not included in the backup.

    Rather than using the --copy-back or the --move-back, each individual InnoDB file-per-table tablespace file will have to be manually imported into the target server. The process that is used to import the file will depend on whether partitioning is involved.

    To restore individual non-partitioned tables from a backup, find the .ibd and .cfg files for the table in the backup, and then import them using the Importing Transportable Tablespaces for Non-partitioned Tables process.

    To restore individual partitions or partitioned tables from a backup, find the .ibd and .cfg files for the partitions in the backup, and then import them using the process.

    When restoring a table with a full-text search (FTS) index, InnoDB may throw a schema mismatch error.

    In this case, to restore the table, it is recommended to:

    • Remove the corresponding .cfg file.

    • Restore data to a table without any secondary indexes including FTS.

    • Add the necessary secondary indexes to the restored table.

    For example, to restore table t1 with FTS index from database db1:

    1. In the MariaDB Command-Line Client, drop the table you are going to restore:

    2. Create an empty table for the data being restored:

    3. Modify the table to discard the tablespace:

    4. In the operating system shell, copy the table files from the backup to the data directory of the corresponding database:

    This page is licensed: CC BY-SA / Gnu FDL

    Restoring Individual Databases From a Full Backup (mariadb-backup)

    Restore a single database from a full backup. Learn the procedure to extract and recover a specific database schema from a larger backup set.

    mariadb-backup was previously called mariabackup.

    This method is to solve a flaw with mariadb-backup; it cannot do single database restores from a full backup easily. There is a blog post that details a way to do this, but it's a manual process which is fine for a few tables but if you have hundreds or even thousands of tables then it would be impossible to do quickly.

    We can't just move the data files to the datadir as the tables are not registered in the engines, so the database will error. Currently, the only effective method is to a do full restore in a test database and then dump the database that requires restoring or running a partial backup.

    This has only been tested with InnoDB. Also, if you have stored procedures or triggers then these will need to be deleted and recreated.

    Some of the issues that this method overcomes:

    • Tables not registered in the InnoDB engine so will error when you try to select from a table if you move the data files into the datadir

    • Tables with foreign keys need to be created without keys, otherwise it will error when you discard the tablespace

    Below is the process to perform a single database restore.

    Firstly, we will need the table structure from a mariadb-dump backup with the --no-data option. I recommend this is done at least once per day or every six hours via a cronjob. As it is just the structure, it are very fast.

    Using SED to return only the table structure we require, then use vim or another text editor to make sure nothing is left.

    Prepare the backup with any incremental-backup-and-restores that you have, and then run the following on the full backup folder using the --export option to generate files with .cfg extensions which InnoDB will look for.

    Once we have done these steps, we can then import the table structure. If you have used the --all-databases option, then you will need to either use SED or open it in a text editor and export out tables that you require. You will also need to log in to the database and create the database if the dump file doesn't. Run the following command below:

    Once the structure is in the database, we have now registered the tables to the engine. Next, we will run the following statements in the information_schema database, to export statements to import/discard table spaces and drop and create foreign keys which we will use later. (edit the CONSTRAINT_SCHEMA and TABLE_SCHEMA WHERE clause to the database you are restoring. Also, add the following lines after your SELECT and before the FROM to have MariaDB export the files to the OS)

    The following are the statements that we will need later.

    Once we have run those statements, and they have been exported to a Linux directory or copied from a GUI interface.

    Run the ALTER DROP KEYS statements in the database.

    Once completed, run the DROP TABLE SPACE statements in the database:

    Exit out the database and change into the directory of the full backup location. Run the following commands to copy all the .cfg and .ibd files to the datadir such as /var/lib/mysql/testdatabase (change the datadir location if needed). Learn more about files that mariadb-backup generates with files-created-by-mariadb-backup.

    After moving the files, it is very important that MySQL is the owner of the files, otherwise it won't have access to them and will error when we import the tablespaces.

    Run the import table spaces statements in the database.

    Run the add key statements in the database

    We have successfully restored a single database. To test that this has worked, we can do a basic check on some tables.

    If you have a primary-replica set up, it would be best to follow the sets above for the primary node and then either take a full mariadb-dump or take a new full mariadb-backup and restore this to the replica. You can find more information about restoring a replica with mariadb-backup in Setting up a Replica with mariadb-backup

    After running the below command, copy to the replica and use the LESS linux command to grab the change master statement. Remember to follow this process: Stop replica > restore data > run CHANGE MASTER statement > start replica again.

    Please follow Setting up a Replica with mariadb-backup on restoring a replica with mariadb-backup:

    For this process to work with Galera cluster, we first need to understand that some statements are not replicated across Galera nodes. One of which is the DISCARD and IMPORT for ALTER TABLES statements, and these statements will need to be ran on all nodes. We also need to run the OS level steps on each server as seen below.

    Run the ALTER DROP KEYS statements on ONE NODE as these are replicated.

    Once completed, run the DROP TABLE SPACE statements on EVERY NODE, as these are not replicated.

    Exit out the database and change into the directory of the full backup location. Run the following commands to copy all the .cfg and .ibd files to the datadir such as /var/lib/mysql/testdatabase (change the datadir location if needed). Learn more about files that mariadb-backup generates with files-created-by-mariadb-backup. This step needs to be done on all nodes. You will need to copy the backup files to each node, we can use the same backup on all nodes.

    After moving the files, it is very important that MySQL is the owner of the files, otherwise it won't have access to them and will error when we import the tablespaces.

    Run the import table spaces statements on EVERY NODE.

    Run the add key statements on ONE NODE.

    This page is licensed: CC BY-SA / Gnu FDL

    RANGE Partitioning Type

    The RANGE partitioning type assigns rows to partitions based on whether column values fall within contiguous, non-overlapping ranges.

    The RANGE partitioning type is used to assign each partition a range of values generated by the partitioning expression. Ranges must be ordered, contiguous and non-overlapping. The minimum value is always included in the first range. The highest value may or may not be included in the last range.

    A variant of this partitioning method, RANGE COLUMNS, allows us to use multiple columns and more datatypes.

    Syntax

    The last part of a CREATE TABLE statement can be definition of the new table's partitions. In the case of RANGE partitioning, the syntax is the following:

    PARTITION BY RANGE (partitioning_expression)
    (
    	PARTITION partition_name VALUES LESS THAN (value),
    	[ PARTITION partition_name VALUES LESS THAN (value), ... ]
    	[ PARTITION partition_name VALUES LESS THAN MAXVALUE ]
    )
    Railroad diagram of RANGE partitioning — equivalent to the BNF above

    PARTITION BY RANGE indicates that the partitioning type is RANGE.

    • partitioning_expression is an SQL expression that returns a value from each row. In the simplest cases, it is a column name. This value is used to determine which partition should contain a row.

    • partition_name is the name of a partition.

    As a catchall, MAXVALUE can be specified as a value for the last partition. Note, however, that in order to append a new partition, it is not possible to use ; instead, must be used.

    A typical use case is when we want to partition a table whose rows refer to a moment or period in time; for example commercial transactions, blog posts, or events of some kind. We can partition the table by year, to keep all recent data in one partition and distribute historical data in big partitions that are stored on slower disks. Or, if our queries always read rows which refer to the same month or week, we can partition the table by month or year week (in this case, historical data and recent data are stored together).

    values also represent a chronological order. So, these values can be used to store old data in separate partitions. However, partitioning by id is not the best choice if we usually query a table by date.

    Partitioning a log table by year:

    Partitioning the table by both year and month:

    In the last example, the function is used to accomplish the purpose. Also, the first two partitions cover longer periods of time (probably because the logged activities were less intensive).

    In both cases, when our tables become huge and we don't need to store all historical data any more, we can drop the oldest partitions in this way:

    We will still be able to drop a partition that does not contain the oldest data, but all rows stored in it will disappear.

    Example of an error when inserting outside a defined partition range:

    To avoid the error, use the IGNORE keyword:

    An alternative definition with MAXVALUE as a catchall:

    This page is licensed: CC BY-SA / Gnu FDL

    DBMS_OUTPUT

    The DBMS_OUTPUT plugin provides Oracle-compatible output buffering functions (like PUT_LINE), allowing stored procedures to send messages to the client.

    This feature is available from MariaDB Enterprise Server 11.8.

    Overview

    Oracle documentation describing DBMS_OUTPUT can be found here: https://docs.oracle.com/en/database/oracle/oracle-database/21/arpls/DBMS_OUTPUT.html

    The main idea of DBMS_OUTPUT is:

    • Messages submitted by DBMS_OUTPUT.PUT_LINE() are not sent to the client until the sending subprogram (or trigger) completes. There is no a way to flush output during the execution of a procedure.

    • Therefore, lines are collected into a server side buffer, which, at the end of the current user statement, can be fetched to the client side using another SQL statement. Then, they can be read using a regular MariaDB Connector-C API. No changes in the client-protocol are needed.

    • Oracle's SQLPlus uses the procedure DBMS_PACKAGE.GET_LINES() to fetch the output to the client side as an array of strings.

    • For JDBC, using GET_LINES() is preferable, because it's more efficient than individual GET_LINE() calls.

    MariaDB implements all routines supported by Oracle, except GET_LINES():

    • Procedure ENABLE() - enable the routines.

    • Procedure DISABLE() - disable the routines. If the package is disabled, all calls to subprograms, such as PUT() and PUT_LINE(), are ignored (or exit immediately without doing anything).

    The package starts in disabled mode, so an explicit enabling is needed:

    If a call for GET_LINE or GET_LINES did not retrieve all lines, then a subsequent call for PUT, PUT_LINE, or NEW_LINE discards the remaining lines (to avoid confusing with the next message). This script demonstrates the principle:

    LINE
    STATUS

    Oracle uses this data type as a storage for the buffer:

    Like Oracle, MariaDB uses an associative array as a storage for the buffer.

    In Oracle, the function GET_LINES() returns an array of strings of this data type:

    MariaDB does not have array data types in the C and C++ connectors, so they can't take advantage of GET_LINES() in a client program.

    Fetching all lines in a PL/SQL program is implemented using a loop of sys.DBMS_OUTPUT.GET_LINE() calls:

    Fetching all lines on the client side (for instance, in a C program using Connector/C) is done by using a loop of sys.DBMS_OUTPUT.GET_LINE() queries.

    Oracle has the following limits:

    • The maximum individual line length (sent to DBMS_OUTPUT) is 32767 bytes.

    • The default buffer size is 20000 bytes. The minimum size is 2000 bytes. The maximum is unlimited.

    MariaDB also implements some limits, either using the total size of all rows or using the row count.

    Like other bootstrap scripts, the script creating DBMS_OUTPUT:

    • Is put into a new separate /scripts/dbms_ouput.sql file in the source directory;

    • Is installed into /share/dbms_ouput.sql of the installation directory.

    \

    Adding & Changing Data Guide

    This guide provides a walkthrough of the INSERT, UPDATE, and DELETE statements, demonstrating how to add, modify, and remove data in tables.

    This guide explains how to add new data and modify existing data in MariaDB using INSERT, REPLACE, and UPDATE statements. Learn about various options for handling duplicates, managing statement priorities, inserting data from other tables, and performing conditional updates.

    The statement is used to add new rows to a table.

    Basic Syntax:

    If providing values for all columns in their defined order:

    The number of values must match the number of columns in table1

    Connecting to MariaDB Guide

    This guide details how to connect to a MariaDB server using the command-line client, covering options for host, user, password, and protocol.

    This guide details the parameters for connecting to a MariaDB server using client programs like mariadb. Learn about default connection behaviors and how to use various command-line options to customize your connection, including secure TLS configurations.

    While the examples focus on the mariadb command-line client, the concepts apply to other clients like graphical interfaces or backup utilities (e.g., mariadb-dump). If you are completely new to MariaDB, refer to first.

    When a connection parameter is not explicitly provided, a default value is used. To connect using only default values with the mariadb

    Advanced Joins

    Explore complex join scenarios. This guide covers filtering joined data with WHERE clauses, handling dates, and aggregating results from multiple tables for deeper analysis.

    This article is a continuation of the . If you're getting started with JOIN statements, review that page first.

    Let us begin by using an example employee database of a fairly small family business, which does not anticipate expanding in the future.

    First, we create the table that will hold all of the employees and their contact information:

    Next, we add a few employees to the table:

    Now, we create a second table, containing the hours which each employee clocked in and out during the week:

    Finally, although it is a lot of information, we add a full week of hours for each of the employees into the second table that we created:

    Configuring MariaDB for Remote Client Access Guide

    Configure MariaDB Server to accept remote connections by setting bind-address, granting privileges for remote users, and opening the right firewall rules.

    This guide explains how to configure your MariaDB server to accept connections from remote hosts. Learn to adjust crucial network settings like bind-address, grant appropriate user privileges for remote connections, and configure essential firewall rules.

    Two main configuration directives control MariaDB's network accessibility:

    • skip-networking: If this directive is enabled, MariaDB will not listen for TCP/IP connections at all. All interaction must be through local mechanisms like Unix sockets or named pipes.

    A MariaDB Primer Guide

    A beginner-friendly primer on using the mariadb command-line client to log in, create databases, and execute basic SQL commands.

    This primer offers a quick jump-start for beginners using an existing MariaDB database via the command-line client. Learn how to log in, understand basic database concepts, and perform essential SQL operations like creating tables, inserting data, and retrieving or modifying records.

    To begin, log into your MariaDB server from your system's command-line:

    • Replace user_name with your MariaDB username.

    Choosing the Right Storage Engine

    A guide to selecting the appropriate storage engine based on data needs, comparing features of general-purpose, columnar, and specialized engines.

    A high-level overview of the main reasons for choosing a particular storage engine:

    • is a good general transaction storage engine, and the best choice in most cases. It is the default storage engine.

    • , MariaDB's more modern improvement on , has a small footprint and allows for easy copying between systems.

    spinner
    DELETE
    REPLACE
    TRUNCATE TABLE

    View (read the value)

    Purpose

    Control and configuration

    Monitoring and diagnostics

    SQL Statement

    SET GLOBAL ... or SET SESSION ...

    SHOW STATUS ...

    CONNECT System Variables
    Spider System Variables
    Spider Status Variables
    Reserved words
    JOIN queries
    SHOW FUNCTION STATUS
    Information Schema ROUTINES Table
    Stored Aggregate Functions
    spatial
    transactions
    virtual columns
    table discovery
    OPTIMIZE TABLE
    REPAIR TABLE
    INSERT DELAYED
    MDEV-15636
    MDEV-16791
    (Outer Join)
    : Returns all rows from the left table, and the matched rows from the right table. If there is no match,
    NULL
    is returned for columns from the right table.
  • RIGHT JOIN (Outer Join): Returns all rows from the right table, and the matched rows from the left table. If there is no match, NULL is returned for columns from the left table. (The example SELECT * FROM t2 LEFT JOIN t1 ... shows this behavior from t1's perspective).

  • INNER JOIN

    CROSS JOIN

    LEFT JOIN (t1 LEFT JOIN t2)

    RIGHT JOIN (t1 RIGHT JOIN t2)

    LEFT JOIN (t2 LEFT JOIN t1) - Simulating a RIGHT JOIN

    Older (Implicit) JOIN Syntax

    Understanding JOIN Types Summary

    Joining Multiple Tables

    See Also

    reorder_outer_joins
    optimizer_switch
    More Advanced Joins
    JOIN Syntax
    Comma vs JOIN
    Joins, Subqueries and SET
    Introduction_to_Joins
    spinner

    Table and Field Aliases

    Placing JOIN Conditions

    Finding Syntax Errors

    Interpreting the Empty Error

    Checking for Keywords

    Version Specific Syntax

    reserved words
    reserved word list
    Basic_Debugging
    spinner

    Backing up the Incremental Changes

    In MariaDB 11.0 and earlier, this file is named xtrabackup_checkpoints. The new name is recognized as a fallback for backups taken with older versions.

    Using the Backup History Table

    Privileges

    Requires SELECT on the history table to find the base backup, and INSERT to record the new one.

    You can also use --incremental-history-uuid if you prefer to reference the unique ID generated by mariadb-backup.

    Combining With --stream Output

    Preparing the Backup

    Restoring the Backup

    stop the MariaDB Server process
    start the MariaDB Server process
    spinner
    see this page
    see this page

    Single Node

    Replica nodes

    Galera Cluster

    spinner
    value
    indicates the upper bound for that partition. The values must be ascending. For the first partition, the lower limit is
    NULL
    . When trying to insert a row, if its value is higher than the upper limit of the last partition, the row are rejected (with an error, if the
    keyword is not used).

    Use Cases

    Examples

    ADD PARTITION
    REORGANIZE PARTITION
    AUTO_INCREMENT
    UNIX_TIMESTAMP
    spinner
    IGNORE
    Procedure PUT_LINE() - submit a line into the internal buffer.
  • Procedure PUT() - submit a partial line into the buffer.

  • Procedure NEW_LINE() - terminate a line submitted by PUT().

  • Procedure GET_LINE() - read one line (the earliest) from the buffer. When a line is read by GET_LINE(), it's automatically removed from the buffer.

  • Procedure GET_LINES() - read all lines (as an array of strings) from the buffer - this procedure isn't implemented.

  • line1

    0

    line3

    0

    -

    1

    Package Routines

    Package Overview

    Details

    Data Type for the Buffer

    Data Type Used for GET_LINES()

    This functionality is not implemented.

    Fetching all Lines in a PL/SQL Program

    Fetching all Lines on the Client Side

    Limits

    Installation

    this section
  • Remove the .cfg file from the data directory:

  • Change the owner of the newly copied files to the system user running MariaDB Server:

  • In the MariaDB Command-Line Client, import the copied tablespace:

  • Verify that the data has been successfully restored:

  • Add the necessary secondary indexes:

  • The table is now fully restored:

  • Using --history with Partial Backups

    You cannot use a partial backup as the base for an incremental backup history chain. The --incremental-history-name option is incompatible with partial backups because restoring partial incrementals requires specific preparation steps (--export) that the history feature does not automate.

    mariadb-backup cannot back up a subset of partitions from a partitioned table. Backing up a partitioned table is an all-or-nothing selection. See MDEV-17132 about that. If you need to backup a subset of partitions, one possibility is that instead of using mariadb-backup, you can export the file-per-table tablespaces of the partitions.

    Preparing the Backup

    Restoring the Backup

    Restoring Individual Non-Partitioned Tables

    Restoring Individual Partitions and Partitioned Tables

    Restoring Individual Tables with Full-Text Indexes

    the --tables option
    MDEV-13466
    Importing Transportable Tablespaces for Partitioned Tables
    spinner
    see this page
    see this page
    Now that we have a cleanly structured database to work with, let us begin this tutorial by stepping up one notch from the last tutorial and filtering our information a little.

    Earlier in the week, an anonymous employee reported that Helmholtz came into work almost four minutes late; to verify this, we will begin our investigation by filtering out employees whose first names are "Helmholtz":

    The result looks like this:

    This is obviously more information than we care to trudge through, considering we only care about when he arrived past 7:00:59 on any given day within this week; thus, we need to add a couple more conditions to our WHERE clause.

    In the following example, we will filter out all of the times which Helmholtz clocked in that were before 7:01:00 and during the work week that lasted from the 8th to the 12th of August:

    The result looks like this:

    By merely adding a few more conditions, we eliminated all of the irrelevant information; Helmholtz was late to work on the 9th and the 12th of August.

    Suppose you would like to—based on the information stored in both of our tables in the employee database—develop a quick list of the total hours each employee has worked for each day recorded; a simple way to estimate the time each employee worked per day is exemplified below:

    The result (limited to 10 rows) looks like this:

    • Joining Tables with JOIN Clauses Guide

    • JOIN Syntax

    • Comma vs JOIN

    • Joins, Subqueries and SET

    The first version of this article was copied, with permission, from More_Advanced_Joins on 2012-10-05.

    This page is licensed: CC BY-SA / Gnu FDL

    The Employee Database

    Working with the Employee Database

    Joining Tables with JOIN Clauses Guide

    Filtering by Name

    Filtering by Name, Date and Time

    Displaying Total Work Hours per Day

    See Also

    spinner
    SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.b;
    +------+------+
    | a    | b    |
    +------+------+
    |    2 |    2 |
    +------+------+
    1 row in set (0.00 sec)
    SELECT * FROM t1 CROSS JOIN t2;
    +------+------+
    | a    | b    |
    +------+------+
    |    1 |    2 |
    |    2 |    2 |
    |    3 |    2 |
    |    1 |    4 |
    |    2 |    4 |
    |    3 |    4 |
    +------+------+
    6 rows in set (0.00 sec)
    SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b;
    +------+------+
    | a    | b    |
    +------+------+
    |    1 | NULL |
    |    2 |    2 |
    |    3 | NULL |
    +------+------+
    3 rows in set (0.00 sec)
    SELECT * FROM t1 RIGHT JOIN t2 ON t1.a = t2.b;
    +------+------+
    | a    | b    |
    +------+------+
    |    2 |    2 |
    | NULL |    4 |
    +------+------+
    2 rows in set (0.00 sec)
    SELECT * FROM t2 LEFT JOIN t1 ON t1.a = t2.b;
    +------+------+
    | b    | a    |
    +------+------+
    |    2 |    2 |
    |    4 | NULL |
    +------+------+
    2 rows in set (0.00 sec)
    SELECT * FROM t1, t2 WHERE t1.a = t2.b;
    SELECT * FROM t1, t2;
    SELECT *
    FROM
        financial_reportQ_1 AS a
        JOIN sales_renderings AS b ON (a.salesGroup = b.groupId)
        JOIN sales_agents AS c ON (b.groupId = c.group)
    WHERE
        b.totalSales > 10000
        AND c.id != a.clientId
    SELECT *
    FROM
        financial_report_Q_1 AS frq1
        JOIN sales_renderings AS sr ON (frq1.salesGroup = sr.groupId)
        JOIN sales_agents AS sa ON (sr.groupId = sa.group)
    WHERE
        sr.totalSales > 10000
        AND sa.id != frq1.clientId
    SELECT *
    FROM
        family,
        relationships
    WHERE
        family.personId = relationships.personId
        AND relationships.relation = 'father'
    SELECT *
    FROM
        family
        JOIN relationships ON (family.personId = relationships.personId)
    WHERE
        relationships.relation = 'father'
    ERROR 1064: You have an error in your SQL syntax; check the manual that corresponds to your
    MariaDB server version for the right syntax to use near ' ' at line 1
    SELECT * FROM someTable WHERE field = 'value
    SELECT * FROM someTable WHERE field = 1 GROUP BY id,
    SELECT * FROM actionTable WHERE `DELETE` = 1;
    SELECT * FROM a, b JOIN c ON a.x = c.x;
    SELECT * FROM someTable WHERE someId IN (SELECT id FROM someLookupTable);
    SELECT * FROM tableA JOIN tableB ON tableA.x = tableB.y;
    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    backup_type = full-backuped
    from_lsn = 0
    to_lsn = 1635102
    last_lsn = 1635102
    recover_binlog_info = 0
    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/inc1/ \
       --incremental-basedir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    backup_type = incremental
    from_lsn = 1635102
    to_lsn = 1635114
    last_lsn = 1635114
    recover_binlog_info = 0
    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/inc2/ \
       --incremental-basedir=/var/mariadb/inc1/ \
       --user=mariadb-backup --password=mypassword
    mariadb-backup --backup --target-dir=/full \
      --history=full_backup_1
    mariadb-backup --backup --target-dir=/inc1 \
      --incremental-history-name=full_backup_1 \
      --history=inc_backup_1
    # initial full backup
    $ mariadb-backup --backup --stream=mbstream \
      --user=mariadb-backup --password=mypassword \
      --extra-lsndir=backup_base | gzip > backup_base.gz
    
    # incremental backup
    $ mariadb-backup --backup --stream=mbstream \
      --incremental-basedir=backup_base \
      --user=mariadb-backup --password=mypassword \
      --extra-lsndir=backup_inc1 | gzip > backup-inc1.gz
    $ mariadb-backup --prepare \
       --target-dir=/var/mariadb/backup
    $ mariadb-backup --prepare \
       --target-dir=/var/mariadb/backup \
       --incremental-dir=/var/mariadb/inc1
    $ mariadb-backup --copy-back \
       --target-dir=/var/mariadb/backup/
    $ chown -R mysql:mysql /var/lib/mysql/
    mariadb-dump -u root -p --all-databases --no-data > nodata.sql
    sed -n '/Current Database: `DATABASENAME`/, /Current Database:/p' nodata.sql > trimednodata.sql
    vim trimednodata.sql
    mariadb-backup --prepare --export --target-dir=/media/backups/fullbackupfolder
    mysql -u root -p schema_name < nodata.sql
    SELECT ...
    INTO OUTFILE '/tmp/filename.SQL'
    FIELDS TERMINATED BY ','
    LINES TERMINATED BY '\n'
    FROM ...
    USE information_schema;
    SELECT concat("ALTER TABLE ",table_name," DISCARD TABLESPACE;")  AS discard_tablespace
    FROM information_schema.tables 
    WHERE TABLE_SCHEMA="DATABASENAME";
    
    SELECT concat("ALTER TABLE ",table_name," IMPORT TABLESPACE;") AS import_tablespace
    FROM information_schema.tables 
    WHERE TABLE_SCHEMA="DATABASENAME";
    
    SELECT 
    CONCAT ("ALTER TABLE ", rc.CONSTRAINT_SCHEMA, ".",rc.TABLE_NAME," DROP FOREIGN KEY ", rc.CONSTRAINT_NAME,";") AS drop_keys
    FROM REFERENTIAL_CONSTRAINTS AS rc
    WHERE CONSTRAINT_SCHEMA = 'DATABASENAME';
    
    SELECT
    CONCAT ("ALTER TABLE ", 
    KCU.CONSTRAINT_SCHEMA, ".",
    KCU.TABLE_NAME," 
    ADD CONSTRAINT ", 
    KCU.CONSTRAINT_NAME, " 
    FOREIGN KEY ", "
    (`",KCU.COLUMN_NAME,"`)", " 
    REFERENCES `",REFERENCED_TABLE_NAME,"` 
    (`",REFERENCED_COLUMN_NAME,"`)" ," 
    ON UPDATE " ,(SELECT UPDATE_RULE FROM REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA)," 
    ON DELETE ",(SELECT DELETE_RULE FROM REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA),";") AS add_keys
    FROM KEY_COLUMN_USAGE AS KCU
    WHERE KCU.CONSTRAINT_SCHEMA = 'DATABASENAME'
    AND KCU.POSITION_IN_UNIQUE_CONSTRAINT >= 0
    AND KCU.CONSTRAINT_NAME NOT LIKE 'PRIMARY';
    ALTER TABLE schemaname.tablename DROP FOREIGN KEY key_name;
    ...
    ALTER TABLE test DISCARD TABLESPACE;
    ...
    cp *.cfg /var/lib/mysql
    cp *.ibd /var/lib/mysql
    sudo chown -R mysql:mysql /var/lib/mysql
    ALTER TABLE test IMPORT TABLESPACE;
    ...
    ALTER TABLE schmeaname.tablename ADD CONSTRAINT key_name FOREIGN KEY (`column_name`) REFERENCES `foreign_table` (`colum_name`) ON UPDATE NO ACTION ON DELETE NO ACTION;
    ...
    USE DATABASE
    SELECT * FROM test LIMIT 10;
    mariadb-dump -u user -p --single-transaction --master-data=2 > fullbackup.sql
    $ mariadb-backup --backup \
       --slave-info --safe-slave-backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    ALTER TABLE schemaname.tablename DROP FOREIGN KEY key_name;
    ...
    ALTER TABLE test DISCARD TABLESPACE;
    ...
    cp *.cfg /var/lib/mysql
    cp *.ibd /var/lib/mysql
    sudo chown -R mysql:mysql /var/lib/mysql
    ALTER TABLE test IMPORT TABLESPACE;
    ...
    ALTER TABLE schmeaname.tablename ADD CONSTRAINT key_name FOREIGN KEY (`column_name`) REFERENCES `foreign_table` (`colum_name`) ON UPDATE NO ACTION ON DELETE NO ACTION;
    ...
    CREATE TABLE log
    (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	dt DATETIME NOT NULL,
    	user INT UNSIGNED,
    	PRIMARY KEY (id, dt)
    )
    	ENGINE = InnoDB
    PARTITION BY RANGE (YEAR(dt))
    (
    	PARTITION p0 VALUES LESS THAN (2013),
    	PARTITION p1 VALUES LESS THAN (2014),
    	PARTITION p2 VALUES LESS THAN (2015),
    	PARTITION p3 VALUES LESS THAN (2016)
    );
    CREATE TABLE log2
    (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	ts TIMESTAMP NOT NULL,
    	user INT UNSIGNED,
    	PRIMARY KEY (id, ts)
    )
    	ENGINE = InnoDB
    PARTITION BY RANGE (UNIX_TIMESTAMP(ts))
    (
    	PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP('2014-08-01 00:00:00')),
    	PARTITION p1 VALUES LESS THAN (UNIX_TIMESTAMP('2014-11-01 00:00:00')),
    	PARTITION p2 VALUES LESS THAN (UNIX_TIMESTAMP('2015-01-01 00:00:00')),
    	PARTITION p3 VALUES LESS THAN (UNIX_TIMESTAMP('2015-02-01 00:00:00'))
    );
    ALTER TABLE log DROP PARTITION p0;
    INSERT INTO log(id,dt) VALUES 
      (1, '2016-01-01 01:01:01'), 
      (2, '2015-01-01 01:01:01');
    ERROR 1526 (HY000): Table has no partition for value 2016
    INSERT IGNORE INTO log(id,dt) VALUES 
      (1, '2016-01-01 01:01:01'), 
      (2, '2015-01-01 01:01:01');
    
    SELECT * FROM log;
    +----+---------------------+------+
    | id | timestamp           | user |
    +----+---------------------+------+
    |  2 | 2015-01-01 01:01:01 | NULL |
    +----+---------------------+------+
    CREATE TABLE log
    (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	dt DATETIME NOT NULL,
    	user INT UNSIGNED,
    	PRIMARY KEY (id, dt)
    )
    	ENGINE = InnoDB
    PARTITION BY RANGE (YEAR(dt))
    (
    	PARTITION p0 VALUES LESS THAN (2013),
    	PARTITION p1 VALUES LESS THAN (2014),
    	PARTITION p2 VALUES LESS THAN (2015),
    	PARTITION p3 VALUES LESS THAN (2016),
    	PARTITION p4 VALUES LESS THAN MAXVALUE
    );
    CALL DBMS_OUTPUT.ENABLE;
    DROP TABLE t1;
    CREATE TABLE t1 (line VARCHAR2(400), status INTEGER);
    DECLARE
      line   VARCHAR2(400);
      status INTEGER;
    BEGIN
      DBMS_OUTPUT.PUT_LINE('line1');
      DBMS_OUTPUT.PUT_LINE('line2');
      DBMS_OUTPUT.GET_LINE(line, status);
      INSERT INTO t1 VALUES (line, status);
      DBMS_OUTPUT.PUT_LINE('line3'); -- This clears the buffer (removes line2) before putting line3
      LOOP
        DBMS_OUTPUT.GET_LINE(line, status);
        INSERT INTO t1 VALUES (line, status);
        EXIT WHEN status <> 0;
      END LOOP;
    END;
    /
    SELECT * FROM t1;
    TYPE CHARARR IS TABLE OF VARCHAR2(32767) INDEX BY BINARY_INTEGER;
    TYPE DBMSOUTPUT_LINESARRAY IS VARRAY(2147483647) OF VARCHAR2(32767);
    SET sql_mode=ORACLE;
    DELIMITER /
    DECLARE
      all_lines MEDIUMTEXT CHARACTER SET utf8mb4 :='';
      line MEDIUMTEXT CHARACTER SET utf8mb4;
      status INT;
    BEGIN
      sys.DBMS_OUTPUT.PUT_LINE('line1');
      sys.DBMS_OUTPUT.PUT_LINE('line2');
      sys.DBMS_OUTPUT.PUT_LINE('line3');
      LOOP
        sys.DBMS_OUTPUT.GET_LINE(line, status);
        EXIT WHEN status > 0;
        all_lines:= all_lines || line || '\n';
      END LOOP;
      SELECT all_lines;
    END;
    /
    DELIMITER ;
    ALTER TABLE table_name REBUILD PARTITION ALL
    $ sudo rm /var/lib/mysql/db1/t1.cfg
    $ sudo chown mysql:mysql /var/lib/mysql/db1/t1.*
    ALTER TABLE db1.t1 IMPORT TABLESPACE;
    SELECT * FROM db1.t1;
    ALTER TABLE db1.t1 FORCE, ADD FULLTEXT INDEX f_idx(f1);
    SHOW CREATE TABLE db1.t1\G
    *************************** 1. row ***************************
           Table: t1
    Create Table: CREATE TABLE `t1` (
      `f1` char(10) DEFAULT NULL,
      FULLTEXT KEY `f_idx` (`f1`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
    $ mariadb-backup --backup \
       --target-dir=/var/mariadb/backup/ \
       --databases='app1 app2' --tables='tab_[0-9]+' \
       --user=mariadb-backup --password=mypassword
    mariadb-backup --backup --databases="db1" \
      --target-dir=/backup --history=partial_db1
    $ mariadb-backup --prepare --export \
       --target-dir=/var/mariadb/backup/
    DROP TABLE IF EXISTS db1.t1;
    CREATE TABLE db1.t1(f1 CHAR(10)) ENGINE=INNODB;
    ALTER TABLE db1.t1 DISCARD TABLESPACE;
    $ sudo cp /data/backups/part/db1/t1.* /var/lib/mysql/db1
    CREATE TABLE `Employees` (
      `ID` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
      `First_Name` VARCHAR(25) NOT NULL,
      `Last_Name` VARCHAR(25) NOT NULL,
      `Position` VARCHAR(25) NOT NULL,
      `Home_Address` VARCHAR(50) NOT NULL,
      `Home_Phone` VARCHAR(12) NOT NULL,
      PRIMARY KEY (`ID`)
    ) ENGINE=MyISAM;
    INSERT INTO `Employees` (`First_Name`, `Last_Name`, `Position`, `Home_Address`, `Home_Phone`)
      VALUES
      ('Mustapha', 'Mond', 'Chief Executive Officer', '692 Promiscuous Plaza', '326-555-3492'),
      ('Henry', 'Foster', 'Store Manager', '314 Savage Circle', '326-555-3847'),
      ('Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456'),
      ('Lenina', 'Crowne', 'Cashier', '281 Bumblepuppy Boulevard', '328-555-2349'),
      ('Fanny', 'Crowne', 'Restocker', '1023 Bokanovsky Lane', '326-555-6329'),
      ('Helmholtz', 'Watson', 'Janitor', '944 Soma Court', '329-555-2478');
    CREATE TABLE `Hours` (
      `ID` TINYINT(3) UNSIGNED NOT NULL,
      `Clock_In` DATETIME NOT NULL,
      `Clock_Out` DATETIME NOT NULL
    ) ENGINE=MyISAM;
    INSERT INTO `Hours`
      VALUES
      ('1', '2005-08-08 07:00:42', '2005-08-08 17:01:36'),
      ('1', '2005-08-09 07:01:34', '2005-08-09 17:10:11'),
      ('1', '2005-08-10 06:59:56', '2005-08-10 17:09:29'),
      ('1', '2005-08-11 07:00:17', '2005-08-11 17:00:47'),
      ('1', '2005-08-12 07:02:29', '2005-08-12 16:59:12'),
      ('2', '2005-08-08 07:00:25', '2005-08-08 17:03:13'),
      ('2', '2005-08-09 07:00:57', '2005-08-09 17:05:09'),
      ('2', '2005-08-10 06:58:43', '2005-08-10 16:58:24'),
      ('2', '2005-08-11 07:01:58', '2005-08-11 17:00:45'),
      ('2', '2005-08-12 07:02:12', '2005-08-12 16:58:57'),
      ('3', '2005-08-08 07:00:12', '2005-08-08 17:01:32'),
      ('3', '2005-08-09 07:01:10', '2005-08-09 17:00:26'),
      ('3', '2005-08-10 06:59:53', '2005-08-10 17:02:53'),
      ('3', '2005-08-11 07:01:15', '2005-08-11 17:04:23'),
      ('3', '2005-08-12 07:00:51', '2005-08-12 16:57:52'),
      ('4', '2005-08-08 06:54:37', '2005-08-08 17:01:23'),
      ('4', '2005-08-09 06:58:23', '2005-08-09 17:00:54'),
      ('4', '2005-08-10 06:59:14', '2005-08-10 17:00:12'),
      ('4', '2005-08-11 07:00:49', '2005-08-11 17:00:34'),
      ('4', '2005-08-12 07:01:09', '2005-08-12 16:58:29'),
      ('5', '2005-08-08 07:00:04', '2005-08-08 17:01:43'),
      ('5', '2005-08-09 07:02:12', '2005-08-09 17:02:13'),
      ('5', '2005-08-10 06:59:39', '2005-08-10 17:03:37'),
      ('5', '2005-08-11 07:01:26', '2005-08-11 17:00:03'),
      ('5', '2005-08-12 07:02:15', '2005-08-12 16:59:02'),
      ('6', '2005-08-08 07:00:12', '2005-08-08 17:01:02'),
      ('6', '2005-08-09 07:03:44', '2005-08-09 17:00:00'),
      ('6', '2005-08-10 06:54:19', '2005-08-10 17:03:31'),
      ('6', '2005-08-11 07:00:05', '2005-08-11 17:02:57'),
      ('6', '2005-08-12 07:02:07', '2005-08-12 16:58:23');
    SELECT
      `Employees`.`First_Name`,
      `Employees`.`Last_Name`,
      `Hours`.`Clock_In`,
      `Hours`.`Clock_Out`
    FROM `Employees`
    INNER JOIN `Hours` ON `Employees`.`ID` = `Hours`.`ID`
    WHERE `Employees`.`First_Name` = 'Helmholtz';
    +------------+-----------+---------------------+---------------------+
    | First_Name | Last_Name | Clock_In            | Clock_Out           |
    +------------+-----------+---------------------+---------------------+
    | Helmholtz  | Watson    | 2005-08-08 07:00:12 | 2005-08-08 17:01:02 |
    | Helmholtz  | Watson    | 2005-08-09 07:03:44 | 2005-08-09 17:00:00 |
    | Helmholtz  | Watson    | 2005-08-10 06:54:19 | 2005-08-10 17:03:31 |
    | Helmholtz  | Watson    | 2005-08-11 07:00:05 | 2005-08-11 17:02:57 |
    | Helmholtz  | Watson    | 2005-08-12 07:02:07 | 2005-08-12 16:58:23 |
    +------------+-----------+---------------------+---------------------+
    5 rows in set (0.00 sec)
    SELECT
      `Employees`.`First_Name`,
      `Employees`.`Last_Name`,
      `Hours`.`Clock_In`,
      `Hours`.`Clock_Out`
    FROM `Employees`
    INNER JOIN `Hours` ON `Employees`.`ID` = `Hours`.`ID`
    WHERE `Employees`.`First_Name` = 'Helmholtz'
    AND DATE_FORMAT(`Hours`.`Clock_In`, '%Y-%m-%d') >= '2005-08-08'
    AND DATE_FORMAT(`Hours`.`Clock_In`, '%Y-%m-%d') <= '2005-08-12'
    AND DATE_FORMAT(`Hours`.`Clock_In`, '%H:%i:%S') > '07:00:59';
    +------------+-----------+---------------------+---------------------+
    | First_Name | Last_Name | Clock_In            | Clock_Out           |
    +------------+-----------+---------------------+---------------------+
    | Helmholtz  | Watson    | 2005-08-09 07:03:44 | 2005-08-09 17:00:00 |
    | Helmholtz  | Watson    | 2005-08-12 07:02:07 | 2005-08-12 16:58:23 |
    +------------+-----------+---------------------+---------------------+
    2 rows in set (0.00 sec)
    SELECT
      `Employees`.`ID`,
      `Employees`.`First_Name`,
      `Employees`.`Last_Name`,
      `Hours`.`Clock_In`,
      `Hours`.`Clock_Out`,
    DATE_FORMAT(`Hours`.`Clock_Out`, '%T')-DATE_FORMAT(`Hours`.`Clock_In`, '%T') 
    AS 'Total_Hours'
    FROM `Employees` 
    INNER JOIN `Hours` ON `Employees`.`ID` = `Hours`.`ID`;
    +----+------------+-----------+---------------------+---------------------+-------------+
    | ID | First_Name | Last_Name | Clock_In            | Clock_Out           | Total_Hours |
    +----+------------+-----------+---------------------+---------------------+-------------+
    |  1 | Mustapha   | Mond      | 2005-08-08 07:00:42 | 2005-08-08 17:01:36 |          10 |
    |  1 | Mustapha   | Mond      | 2005-08-09 07:01:34 | 2005-08-09 17:10:11 |          10 |
    |  1 | Mustapha   | Mond      | 2005-08-10 06:59:56 | 2005-08-10 17:09:29 |          11 |
    |  1 | Mustapha   | Mond      | 2005-08-11 07:00:17 | 2005-08-11 17:00:47 |          10 |
    |  1 | Mustapha   | Mond      | 2005-08-12 07:02:29 | 2005-08-12 16:59:12 |           9 |
    |  2 | Henry      | Foster    | 2005-08-08 07:00:25 | 2005-08-08 17:03:13 |          10 |
    |  2 | Henry      | Foster    | 2005-08-09 07:00:57 | 2005-08-09 17:05:09 |          10 |
    |  2 | Henry      | Foster    | 2005-08-10 06:58:43 | 2005-08-10 16:58:24 |          10 |
    |  2 | Henry      | Foster    | 2005-08-11 07:01:58 | 2005-08-11 17:00:45 |          10 |
    |  2 | Henry      | Foster    | 2005-08-12 07:02:12 | 2005-08-12 16:58:57 |           9 |
    +----+------------+-----------+---------------------+---------------------+-------------+
    10 rows in set (0.00 sec)
    .

    Specifying Columns:

    It's good practice to specify the columns you are inserting data into, which also allows you to insert columns in any order or omit columns that have default values or allow NULL.

    • The INTO keyword is optional but commonly used for readability.

    • If a column is not listed and is an AUTO_INCREMENT key, its value will be generated. For other omitted columns, their DEFAULT value will be used, or NULL if allowed. You can explicitly insert a default value using the DEFAULT keyword in the VALUES list for a specific column.

    Multiple Row Inserts:

    Insert multiple rows in a single statement for efficiency:

    The VALUES keyword is used only once, with each row's values enclosed in parentheses and separated by commas.

    Handling Duplicates with INSERT IGNORE:

    If you attempt to insert a row that would cause a duplicate value in a PRIMARY KEY or UNIQUE index, an error normally occurs, and the row (and potentially subsequent rows in a multi-row insert) might not be inserted.

    Using IGNORE tells MariaDB to discard the duplicate row(s) and continue inserting any other valid rows without generating an error.

    LOW_PRIORITY:

    An INSERT statement normally takes priority over SELECT statements, potentially locking the table and making other clients wait. LOW_PRIORITY makes the INSERT wait until no other clients are reading from the table.

    • Once the LOW_PRIORITY insert begins, it will lock the table as usual. New read requests that arrive while it's waiting will be processed before it.

    DELAYED:

    INSERT DELAYED lets the server queue the insert request and return control to the client immediately; the rows are written when the table is not in use, and inserts from many clients are batched together.

    • DELAYED works only with non-transactional storage engines — MyISAM, MEMORY, ARCHIVE, BLACKHOLE, non-transactional Aria, and OQGRAPH. Using it with another engine returns an error.

    • It is controlled by the max_delayed_threads system variable; setting that to 0 disables DELAYED.

    • Because control returns before the rows are written, there is no confirmation of success, and queued rows held in memory are lost if the server stops before they are written. See for the full list of limitations.

    You can insert rows into a table based on data retrieved from another table (or tables) using INSERT ... SELECT.

    • The columns in the INSERT INTO softball_team (...) list must correspond in number and general data type compatibility to the columns in the SELECT list.

    • INSERT...SELECT statements generally cannot operate on the exact same table as both the target and the source directly without mechanisms like temporary tables or certain subquery structures.

    The REPLACE statement works like INSERT, but if a new row has the same value as an existing row for a PRIMARY KEY or a UNIQUE index, the existing row is deleted before the new row is inserted. If no such conflict exists, it acts like a normal INSERT.

    • Flags like LOW_PRIORITY work similarly to INSERT.

    • REPLACE also supports the REPLACE ... SELECT syntax.

    • Because REPLACE performs a delete then an insert, any columns in the table not specified in the REPLACE statement will receive their default values for the newly inserted row, not values from the old row.

    Use the UPDATE statement to change data in existing rows.

    Basic Syntax:

    • The SET clause specifies which columns to modify and their new values.

    • The WHERE clause is crucial; it determines which rows are updated. Without a WHERE clause, all rows in the table will be updated.

    • LOW_PRIORITY and IGNORE (to ignore errors like unique key violations during update, allowing other valid row updates to proceed) can also be used with UPDATE.

    Using Current Column Values in an Update:

    You can use a column's current value in the calculation for its new value.

    ORDER BY and LIMIT with UPDATE:

    You can control the order in which rows are updated and limit the number of rows affected (for single-table updates).

    This updates the 10 most recently created 'pending' rows.

    Multi-Table UPDATE:

    You can update rows in one table based on values from another table by joining them.

    • Here, products.stock_count is updated using values from stock_levels.

    • ORDER BY and LIMIT are generally not allowed with multi-table UPDATE statements in this direct join form.

    This powerful feature allows you to INSERT ... ON DUPLICATE KEY UPDATE a new row, but if a duplicate key (Primary or Unique) conflict occurs, it performs an UPDATE on the existing row instead.

    • If id '1012' does not exist, the row is inserted with status_column = 'new'.

    • If id '1012' already exists, the existing row is updated: status_column is set to 'old', and col2 is updated with the value that would have been inserted for col2 (using VALUES(col2)).

    • The IGNORE keyword can be used with INSERT ... ON DUPLICATE KEY UPDATE to ignore errors that might occur during the UPDATE part if the update itself causes a problem (though this is less common). If IGNORE is used with INSERT and ON DUPLICATE KEY UPDATE is also present, IGNORE only applies to the INSERT part, not the UPDATE part.

    Beyond these SQL statements, MariaDB offers bulk methods for adding data, such as:

    • LOAD DATA INFILE: For importing data from text files.

    • mariadb-import utility: A command-line tool that uses LOAD DATA INFILE. These are covered in the Importing Data Guide.

    This page is licensed: CC BY-SA / Gnu FDL

    INSERT table1 VALUES('value1','value2','value3');

    Adding Data with INSERT

    INSERT
    INSERT INTO table1 (col3, col1) VALUES('value_for_col3', 'value_for_col1');
    INSERT INTO table2 (id_col, data_col1, data_col2) VALUES
      ('id1', 'text_a', 'text_b'),
      ('id2', 'text_c', 'text_d'),
      ('id3', 'text_e', 'text_f');
    INSERT IGNORE INTO table2 (unique_id_col, data_col) VALUES
      ('id1', 'some_data'),        -- Will be inserted if new
      ('id2', 'other_data'),       -- Will be inserted if new
      ('id1', 'duplicate_data');  -- Will be ignored if 'id1' already exists or was just inserted
    INSERT LOW_PRIORITY INTO table1 VALUES('value1','value2','value3');
    INSERT DELAYED INTO table1 VALUES('value1','value2','value3');
    INSERT INTO softball_team (last_name, first_name, telephone)
      SELECT name_last, name_first, tel_home
      FROM company_database.employees
      WHERE is_on_softball_team = 'Y';
    REPLACE LOW_PRIORITY INTO table2 (id_col, data_col1, data_col2) VALUES
      ('id1', 'new_text_a', 'new_text_b'), -- If 'id1' exists, old row is deleted, this is inserted
      ('id2', 'new_text_c', 'new_text_d'), -- If 'id2' doesn't exist, this is inserted
      ('id3', 'new_text_e', 'new_text_f');
    UPDATE table3
    SET col1 = 'new_value_a', col2 = 'new_value_b'
    WHERE id_column < 100;
    UPDATE table5
    SET event_date = DATE_ADD(event_date, INTERVAL 1 DAY)
    WHERE DAYOFWEEK(event_date) = 1; -- Example: Add 1 day if event_date is a Sunday
    UPDATE LOW_PRIORITY table3
    SET col1 = 'updated_text_a', col2 = 'updated_text_b'
    WHERE status_column = 'pending'
    ORDER BY creation_date DESC
    LIMIT 10;
    UPDATE products p
    JOIN stock_levels s ON p.product_id = s.product_id
    SET p.stock_count = s.current_stock
    WHERE s.warehouse_id = 'WHA';
    INSERT INTO table1 (id, col1, col2, status_column)
    VALUES ('1012', 'some_text', 'other_text', 'new')
    ON DUPLICATE KEY UPDATE status_column = 'old', col2 = VALUES(col2);

    Managing INSERT Priority and Behavior

    Inserting Data from Another Table (INSERT...SELECT)

    Replacing Data with REPLACE

    Modifying Data with UPDATE

    Conditional Inserts or Updates (INSERT ... ON DUPLICATE KEY UPDATE)

    Further Data Modification Methods

    spinner
    client:

    In this scenario, the following defaults typically apply:

    • Host name: localhost

    • User name: Your Unix login name (on Unix-like systems) or ODBC (on Windows).

    • Password: No password is sent.

    • Database: The client connects to the server but not to a specific database by default.

    • Socket: The default socket file is used for connection.

    You can override these defaults by specifying parameters. For example:

    In this example:

    • -h 166.78.144.191: Specifies the host IP address instead of localhost.

    • -u username: Specifies username as the MariaDB user.

    • -ppassword: Specifies password as the password.

      • Note: For passwords, there must be no space between -p and the password value.

      • Security Warning: Providing a password directly on the command line is insecure as it can be visible to other users on the system. It's more secure to use -p without the password value, which will prompt you to enter it.

    • database_name: This is the name of the database to connect to, provided as the first argument after all options.

    • The connection will use the default TCP/IP port (usually 3306).

    The following are common connection parameters:

    • --host=name

    • -h name

    Connects to the MariaDB server on the given host.

    Default: localhost.

    MariaDB typically does not permit remote logins by default; see Configuring MariaDB for Remote Client Access.

    • --password[=passwd]

    • -p[passwd]

    Specifies the password for the MariaDB account.

    • Security Best Practice: For improved security, use the -p or --password option without providing the password value directly on the command line. You will be prompted to enter it, preventing it from being visible in command history or process lists.

    • --pipe

    • -W

    (Windows only) Connects to the server using a named pipe, if the server was started with the --enable-named-pipe option.

    • --port=num

    • -P num

    Specifies the TCP/IP port number for the connection.

    Default: 3306.

    • --protocol=name

    Specifies the connection protocol. Possible values (case-insensitive): TCP, SOCKET, PIPE, MEMORY. The default protocol is typically the most efficient for the operating system (e.g., SOCKET on Unix).

    • TCP: TCP/IP connection (local or remote). Available on all OS.

    • SOCKET: Unix socket file connection (local server on Unix systems only). If --socket is not specified, the default is /tmp/mysql.sock.

    • PIPE: Named-pipe connection (local or remote). Windows only.

    • MEMORY: Shared-memory connection (local server on Windows systems only).

    • --shared-memory-base-name=name

    (Windows only) Specifies the shared-memory name for connecting to a local server started with the --shared-memory option. The value is case-sensitive.

    Default: MARIADB.

    • --socket=name

    • -S name

    For connections to localhost:

    • On Unix: Specifies the Unix socket file to use. Default: /tmp/mysql.sock.

    • On Windows: Specifies the name (case-insensitive) of the named pipe if the server was started with --enable-named-pipe. Default: MARIADB.

    • --user=name

    • -u name

    Specifies the MariaDB user name for the connection.

    Default: Your Unix login name (on Unix-like systems) or ODBC (on Windows).

    See the GRANT command for information on creating MariaDB user accounts.

    These options control the use of TLS (Transport Layer Security) for secure connections. For comprehensive details, see Secure Connections Overview and TLS System Variables.

    • --ssl: Enable TLS for the connection. Automatically enabled if other --ssl-* flags are used. Disable with --skip-ssl.

    • --ssl-ca=name: CA (Certificate Authority) file in PEM format. (Implies --ssl).

    • --ssl-capath=name: Directory containing CA certificates in PEM format. (Implies --ssl).

    • --ssl-cert=name: Client X.509 certificate in PEM format. (Implies --ssl).

    • --ssl-cipher=name: Specific TLS cipher(s) to use for the connection. (Implies --ssl).

    • --ssl-key=name: Client X.509 private key in PEM format. (Implies --ssl).

    • --ssl-crl=name: Certificate Revocation List (CRL) file in PEM format. (Implies --ssl).

    • --ssl-crlpath=name: Directory containing CRL files. (Implies --ssl).

    • --ssl-verify-server-cert: Verifies the server's certificate "Common Name" against the hostname used for connecting. Disabled by default.

    Connection parameters and other options can also be set in option files (configuration files), which most MariaDB clients read upon startup. To see which option files a client reads and the option groups it recognizes, typically run the client with the --help option.

    • A MariaDB Primer

    • mariadb client

    • Clients and Utilities

    • Configuring MariaDB for Remote Client Access

    • allows you to start MariaDB without GRANT. This is useful if you lost your root password.

    This page is licensed: CC BY-SA / Gnu FDL

    Default Connection Behavior

    A MariaDB Primer

    WEBINAR

    MariaDB 101: Learning the Basics of MariaDB

    mariadb
    mariadb -h 166.78.144.191 -u username -ppassword database_name

    Overriding Defaults

    Connection Parameters

    host

    password

    pipe

    port

    protocol

    shared-memory-base-name

    socket

    user

    TLS Options

    Option Files

    See Also

    bind-address: This directive specifies the IP address the server listens on.

    • By default, for security, many MariaDB packages bind to 127.0.0.1 (localhost). This means the server will only accept connections originating from the server machine itself via the loopback interface. Remote connections will fail.

    • If bind-address is set to 127.0.0.1, attempting to connect from another host, or even from the same host using a non-loopback IP address, will result in errors like:

      A telnet myhost 3306 test would likely show "Connection refused."

    • To allow connections from other hosts, you must either comment out the bind-address directive (making MariaDB listen on all available network interfaces, i.e., 0.0.0.0 for IPv4), or set it to a specific public IP address of the server.

    • MariaDB 10.11 and later: bind-address can accept multiple comma-separated IP addresses, allowing the server to listen on specific interfaces while excluding others.

    Connecting via localhost typically works even if bind-address is 127.0.0.1 (using the loopback interface):

    Locating the MariaDB Configuration File

    To change these network settings, you need to edit MariaDB's configuration file (often named my.cnf or my.ini).

    • See Configuring MariaDB with my.cnf for comprehensive details.

    • Common Locations:

      • /etc/my.cnf (Unix/Linux/BSD)

      • /etc/mysql/my.cnf (Common on Debian/Ubuntu)

      • $MYSQL_HOME/my.cnf (Unix/Linux/BSD, where $MYSQL_HOME is MariaDB's base directory)

      • SYSCONFDIR/my.cnf (Compile-time specified system configuration directory)

      • DATADIR\my.ini (Windows, in the data directory)

      • ~/.my.cnf (User-specific configuration file)

    • Identifying Loaded Files: To see which configuration files your mariadbd server instance reads and in what order, execute:

      Bash

      Look for a line similar to: Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf

    1. Open the File: Use a text editor to open the primary configuration file identified (e.g., /etc/mysql/my.cnf).

    2. Locate [mysqld] Section: Find the section starting with [mysqld].

    3. Adjust Directives:

      • If skip-networking is present and enabled (not commented out with #), comment it out or set it to 0:Ini, TOML

        orIni, TOML

      • If bind-address = 127.0.0.1 (or another loopback/specific IP that's too restrictive) is present:

    4. Save and Restart: Save the configuration file and restart the MariaDB server service.

      • See for instructions.

    5. Verify Settings (Optional): You can check the options mariadbd is effectively using by running:

      Look for the effective bind-address value or the absence of skip-networking. If multiple [mysqld] sections or skip-bind-address are used, the last specified prevailing value is typically what counts.

    Configuring the server to listen for remote connections is only the first step. You must also grant privileges to user accounts to connect from specific remote hosts. MariaDB user accounts are defined as 'username'@'hostname'.

    1. Connect to MariaDB:

      mariadb -u root -p
    2. **View Existing Remote Users (Optional):**SQL

      SELECT User, Host FROM mysql.user 
      WHERE Host <> 'localhost' AND Host <> '127.0.0.1' AND Host <> '::1';
    3. Grant Privileges: Use the GRANT statement to allow a user to connect from a remote host or a range of hosts.

      • Syntax Elements:

        • Privileges (e.g., ALL PRIVILEGES, SELECT, INSERT, UPDATE)

        • Database/tables (e.g., database_name.* for all tables in a database, *.* for all databases)

      • Example: Grant root-like access from a specific LAN subnet: It's highly discouraged to allow root access from all hosts ('root'@'%') directly to the internet. Instead, restrict it to trusted networks if necessary.

        SQL

        This allows the root user to connect from any IP address in the 192.168.100.x subnet. Replace 'my-very-strong-password'

      • For creating less privileged users or more granular permissions, see the documentation.

    Even if MariaDB is configured for remote access, a firewall on the server (software or hardware) might block incoming connections on MariaDB's port (default is 3306).

    • RHEL/CentOS 7 Example (using firewall-cmd):

      sudo firewall-cmd --add-port=3306/tcp --permanent
      sudo firewall-cmd --reload

      The first command adds the rule, the second makes it persist after reboots and applies the changes. Consult your OS/firewall documentation for specific commands.

    • Security: Opening MariaDB to remote connections, especially to the internet, increases security risks. Always use strong passwords, grant minimal necessary privileges, and restrict host access as much as possible. Consider using TLS/SSL for encrypted connections (see Secure Connections Overview).

    • Reverting: To disable remote access and revert to a more secure local-only setup:

      1. Edit your MariaDB configuration file.

      2. Ensure skip-networking is not enabled (or is 0).

      3. Set bind-address = 127.0.0.1 explicitly, or remove any skip-bind-address directive if you previously added it to listen on all interfaces. The goal is to have bind-address=127.0.0.1 as the effective setting.

      4. Restart the MariaDB server.

      5. Review and revoke any unnecessary remote GRANT privileges.

    The initial version of this article was copied, with permission, from Remote_Clients_Cannot_Connect on 2012-10-30.

    This page is licensed: CC BY-SA / Gnu FDL

    Understanding Key Network Directives

    ./client/mariadb --host=localhost --protocol=tcp --port=3306 test

    Modifying the Configuration File for Remote Access

    Granting User Privileges for Remote Connections

    Configuring Your Firewall

    Important Considerations and Reverting Changes

    spinner

    Replace ip_address with the hostname or IP address of your MariaDB server. If you are accessing MariaDB from the same server you're logged into (locally = localhost), you can usually omit the -h ip_address part.

  • Replace db_name with the name of the database you wish to access (for instance, test). Some setups may have a test database by default; others might not, or it might have been removed (for instance, by mariadb-secure-installation). If unsure, or if you want to connect without selecting a specific database initially, you can omit db_name.

  • You are prompted to enter your password. If your login is successful, you see a prompt similar to this:

    "MariaDB" indicates you are connected to a MariaDB server. The name within the brackets (for instance, test) is your current default database. If no database was specified or successfully connected to, it shows [(none)].

    SQL (Structured Query Language): This is the language used to interact with MariaDB. An SQL statement that requests data is called a query.

    Tables: Databases store information in tables, which are structured like spreadsheets with rows and columns, but are much more efficient for data management.

    Example Setup:

    If the test database is empty or doesn't exist, you can run the following SQL statements to create and populate tables for the examples in this primer. Copy and paste these into the mariadb client prompt.

    • Semicolons (;): The mariadb client allows complex SQL statements over multiple lines. It sends the statement to the server for execution only after you type a semicolon (;) and press [Enter].

    Listing Tables:

    To see the tables in your current database:

    Output (example):

    Describing a Table:

    To get information about the columns in a table (like their names and types):

    Output (example):

    The Field column lists the column names, which you'll need to retrieve specific data.

    To retrieve data from a table, use the SELECT statement.

    • The asterisk (*) is a wildcard meaning "all columns." Output (example):

    To add new rows to a table, use the INSERT statement.

    • After INSERT INTO table_name, list the columns you are providing data for in parentheses.

    • The VALUES keyword is followed by a list of values in parentheses, in the same order as the listed columns. Output:

    You can run SELECT * FROM books; again to see the newly added row.

    To change existing data in a table, use the UPDATE statement. Let's correct the spelling of "The Hobbbit".

    • SET Title = "The Hobbit" specifies the column to change and its new value.

    • WHERE BookID = 7 is crucial; it specifies which row(s) to update. Without a WHERE clause, UPDATE would change all rows in the table. Output:

    Run SELECT * FROM books WHERE BookID = 7; to see the correction.

    Using MariaDB involves understanding SQL syntax. It doesn't allow for typing mistakes or clauses in the wrong order, but with practice, it becomes straightforward.

    • MariaDB Basics

    mariadb -u user_name -p -h ip_address db_name

    Logging into MariaDB

    mariadb

    WEBINAR

    MariaDB 101: Learning the Basics of MariaDB

    MariaDB [test]>
    CREATE DATABASE IF NOT EXISTS test;
    USE test;
    
    CREATE TABLE IF NOT EXISTS books (
      BookID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
      Title VARCHAR(100) NOT NULL,
      SeriesID INT,
      AuthorID INT
    );
    
    CREATE TABLE IF NOT EXISTS authors (
      id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
      -- You would typically add more columns like name, etc.
    );
    
    CREATE TABLE IF NOT EXISTS series (
      id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
      -- You would typically add more columns like series_name, etc.
    );
    
    INSERT INTO books (Title, SeriesID, AuthorID) VALUES
      ('The Fellowship of the Ring', 1, 1),
      ('The Two Towers', 1, 1),
      ('The Return of the King', 1, 1),
      ('The Sum of All Men', 2, 2),
      ('Brotherhood of the Wolf', 2, 2),
      ('Wizardborn', 2, 2),
      ('The Hobbbit', 0, 1); -- Note: "Hobbbit" is intentionally misspelled for a later example
    SHOW TABLES;
    +----------------+
    | Tables_in_test |
    +----------------+
    | authors        |
    | books          |
    | series         |
    +----------------+
    3 rows in set (0.00 sec)
    DESCRIBE books;
    +----------+--------------+------+-----+---------+----------------+
    | Field    | Type         | Null | Key | Default | Extra          |
    +----------+--------------+------+-----+---------+----------------+
    | BookID   | int(11)      | NO   | PRI | NULL    | auto_increment |
    | Title    | varchar(100) | NO   |     | NULL    |                |
    | SeriesID | int(11)      | YES  |     | NULL    |                |
    | AuthorID | int(11)      | YES  |     | NULL    |                |
    +----------+--------------+------+-----+---------+----------------+
    SELECT * FROM books;
    +--------+----------------------------+----------+----------+
    | BookID | Title                      | SeriesID | AuthorID |
    +--------+----------------------------+----------+----------+
    |      1 | The Fellowship of the Ring |        1 |        1 |
    |      2 | The Two Towers             |        1 |        1 |
    |      3 | The Return of the King     |        1 |        1 |
    |      4 | The Sum of All Men         |        2 |        2 |
    |      5 | Brotherhood of the Wolf    |        2 |        2 |
    |      6 | Wizardborn                 |        2 |        2 |
    |      7 | The Hobbbit                |        0 |        1 |
    +--------+----------------------------+----------+----------+
    7 rows in set (0.00 sec)
    INSERT INTO books (Title, SeriesID, AuthorID)
    VALUES ("Lair of Bones", 2, 2);
    Query OK, 1 row affected (0.00 sec)
    UPDATE books
    SET Title = "The Hobbit"
    WHERE BookID = 7;
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1  Changed: 1  Warnings: 0

    Understanding Database Basics and Setup

    Exploring Your Database Structure

    Retrieving Data (SELECT)

    Adding Data (INSERT)

    Modifying Data (UPDATE)

    See Also

    MyISAM has a small footprint and allows for easy copying between systems. MyISAM is MySQL's oldest storage engine. There is usually little reason to use it except for legacy purposes. Aria is MariaDB's more modern improvement.

  • XtraDB is no longer available. It was a performance-enhanced fork of InnoDB and was MariaDB's default engine until .

  • When you want to split your database load on several servers or optimize for scaling. We also suggest looking at , a synchronous multi-master cluster.

    • Spider uses partitioning to provide data sharding through multiple servers.

    • utilizes a massively parallel distributed data architecture and is designed for big data scaling to process petabytes of data.

    • The MERGE storage engine is a collection of identical MyISAM tables that can be used as one. "Identical" means that all tables have identical column and index information.

    • MyRocks enables greater compression than InnoDB, as well as less write amplification giving better endurance of flash storage and improving overall throughput.

    • The Archive storage engine is, unsurprisingly, best used for archiving.

    When you want to use data not stored in a MariaDB database.

    • The CSV storage engine can read and append to files stored in CSV (comma-separated-values) format. However, since MariaDB 10.0, CONNECT is a better choice and is more flexibly able to read and write such files.

    Search engines optimized for search.

    • SphinxSE is used as a proxy to run statements on a remote Sphinx database server (mainly useful for advanced fulltext searches).

    • Mroonga provides fast CJK-ready full text searching using column store.

    • MEMORY does not write data on-disk (all rows are lost on crash) and is best-used for read-only caches of data from other tables, or for temporary work areas. With the default InnoDB and other storage engines having good caching, there is less need for this engine than in the past.

    • S3 Storage Engine is a read-only storage engine that stores its data in Amazon S3.

    • Sequence allows the creation of ascending or descending sequences of numbers (positive integers) with a given starting value, ending value and increment, creating virtual, ephemeral tables automatically when you need them.

    • The BLACKHOLE storage engine accepts data but does not store it and always returns an empty result. This can be useful in replication environments, for example, if you want to run complex filtering rules on a slave without incurring any overhead on a master.

    • allows you to handle hierarchies (tree structures) and complex graphs (nodes having many connections in several directions).

    • The storage engine is an aggregated, extensible engine suitable for what-if analyses in MariaDB. The name is derived from [VI]rtual in[DEX]. Using VIDEX, you can evaluate how potential indexes (and optimizer decisions such as join orders) would change query plans without creating real indexes on production data.

    • The Archive storage engine is, unsurprisingly, best used for archiving.

    • Aria, MariaDB's more modern improvement on MyISAM, has a small footprint and allows for easy copy between systems.

    • The BLACKHOLE storage engine accepts data but does not store it and always returns an empty result. This can be useful in replication environments, for example, if you want to run complex filtering rules on a slave without incurring any overhead on a master.

    • utilizes a massively parallel distributed data architecture and is designed for big data scaling to process petabytes of data.

    • allows access to different kinds of text files and remote resources as if they were regular MariaDB tables.

    • The storage engine can read and append to files stored in CSV (comma-separated-values) format. However, since MariaDB 10.0, CONNECT is a better choice and is more flexibly able to read and write such files.

    • is a good general transaction storage engine, and the best choice in most cases. It is the default storage engine.

    • The storage engine is a collection of identical MyISAM tables that can be used as one. "Identical" means that all tables have identical column and index information.

    • does not write data on-disk (all rows are lost on crash) and is best-used for read-only caches of data from other tables, or for temporary work areas. With the default and other storage engines having good caching, there is less need for this engine than in the past.

    • provides fast CJK-ready full text searching using column store.

    • has a small footprint and allows for easy copying between systems. MyISAM is MySQL's oldest storage engine. There is usually little reason to use it except for legacy purposes. Aria is MariaDB's more modern improvement.

    • enables greater compression than InnoDB, as well as less write amplification giving better endurance of flash storage and improving overall throughput.

    • allows you to handle hierarchies (tree structures) and complex graphs (nodes having many connections in several directions).

    • is a read-only storage engine that stores its data in Amazon S3.

    • allows the creation of ascending or descending sequences of numbers (positive integers) with a given starting value, ending value and increment, creating virtual, ephemeral tables automatically when you need them.

    • is used as a proxy to run statements on a remote Sphinx database server (mainly useful for advanced fulltext searches).

    • uses partitioning to provide data sharding through multiple servers.

    • The storage engine is an aggregated, extensible engine suitable for what-if analyses in MariaDB.

    This page is licensed: CC BY-SA / Gnu FDL

    Topic List

    General Purpose

    InnoDB
    Aria
    MyISAM

    Scaling, Partitioning

    Compression / Archive

    Connecting to Other Data Sources

    Search Optimized

    Cache, Read-only

    Other Specialized Storage Engines

    Alphabetical List

    spinner
    Stored Routine Privileges
    SHOW FUNCTION STATUS
    Information Schema ROUTINES Table

    Basics Guide

    Complete MariaDB basics guide: connect with mariadb -u/-p/-h, CREATE DATABASE/USE, CREATE TABLE with AUTO_INCREMENT, INSERT/SELECT/UPDATE/DELETE commands.

    The quickstart guide walks you through connecting to a MariaDB server, creating your initial database and table structures, and performing fundamental data operations. It's designed for new users or anyone needing a quick refresher on essential MariaDB commands and basic syntax.

    Connecting to MariaDB Server

    To interact with the MariaDB server, use a client program. The default command-line client is mariadb.

    Connect to MariaDB in monitor mode from the Linux command-line:

    mariadb -u root -p -h localhost

    Common options:

    • -u username: Specifies the MariaDB user (e.g., root). This is not the OS user.

    • -p: Prompts for the password. If no password is set, press [Enter].

    • -h hostname_or_IP: Specifies the server's hostname or IP address if the client is on a different machine than the server. Often not needed if connecting locally.

    If logged into Linux as root, you might only need:

    To exit the mariadb monitor, type quit or exit and press [Enter].

    First, create and select a database.

    This creates a database named bookstore and sets it as the default for subsequent operations.

    Next, create tables to hold data.

    This statement creates a books table with six columns:

    • isbn: CHAR(20), the primary key for unique identification.

    • title: VARCHAR(50), a variable-width string for the book title.

    To view the structure of a created table:

    To modify an existing table, use the ALTER TABLE statement (see ). To delete a table and all its data (irreversibly), use DROP TABLE table_name; (see ).

    Example of another table, authors, using AUTO_INCREMENT for the primary key:

    The author_id will automatically generate a unique number for each new author.

    • SQL statements typically end with a semicolon (;) or \G.

    • Statements can span multiple lines; execution occurs after the terminating character and [Enter].

    • To cancel a partially typed statement in the mariadb client, enter \c

    Use the INSERT statement (see ) to add new rows to a table.

    Since author_id in the authors table is AUTO_INCREMENT (see ), its value is assigned automatically. If not all columns are being supplied with data, the column names must be listed, followed by their corresponding values in the VALUES clause.

    To insert data for a book, referencing author_id 1 (assuming Kafka's author_id became 1):

    Multiple rows can be inserted with a single INSERT statement:

    Use the SELECT statement (see SELECT documentation) to query data from tables.

    To retrieve all book titles:

    To limit the number of rows returned (e.g., to 5) using LIMIT (see ):

    To retrieve data from multiple tables, use a JOIN (see ). This example lists book titles and author last names by joining books and authors on their common author_id column:

    To filter results, use the WHERE clause. This example finds books by 'Kafka' and renames the title column1 in the output to 'Kafka Books' using AS (an alias):

    To modify existing data, use the UPDATE statement (see ). Always use a WHERE clause to specify which rows to update.

    This changes the title for the book with the specified isbn. Multiple columns can be updated by separating column = value assignments with commas within the SET clause.

    To remove rows from a table, use the DELETE statement (see ). Use WHERE to specify which rows to delete.

    This deletes all books associated with author_id '2034'.

    This page is licensed: CC BY-SA / Gnu FDL

    Creating & Using Views Guide

    Discover how to create and use views to simplify complex queries, restrict data access, and present a specific perspective of your data.

    This guide introduces SQL Views in MariaDB, virtual tables based on the result-set of a stored query. Learn how views simplify complex queries, enhance data security by restricting access, and provide an abstraction layer over your database tables through practical examples.

    Prerequisites

    • A basic understanding of SQL, particularly JOIN operations. (You may want to refer to More Advanced Joins.)

    • Access to a MariaDB database.

    • Privileges to CREATE TABLE and .

    First, we'll create and populate two tables, Employees and Hours, to use in our examples. If you have already completed a tutorial using this database structure (e.g., from a "More Advanced Joins" guide), you might be able to skip this setup.

    Employees Table:

    Hours Table:

    Let's say Human Resources needs a report on employees who are late (clock in after 7:00:59 AM) and do not make up the time at the end of their shift (work less than 10 hours and 1 minute).

    Initial Query (Helmholtz's Lateness):

    This query finds instances where Helmholtz was late within a specific week:

    Output:

    Refined Query (Policy Violators):

    This query identifies all employees who were late and whose shift duration was less than 10 hours and 1 minute (601 minutes).

    Output of Refined Query (example structure):

    The refined query is becoming complex. Storing this query logic in application code makes it harder to manage and means changes to table structures require application code changes. Views can simplify this.

    A view is a virtual table based on the result-set of a stored query.

    Creating the Employee_Tardiness View:

    We use the refined query to create a view. SQL SECURITY INVOKER means the view runs with the permissions of the user querying it.

    Querying the View:

    Now, retrieving the tardiness data is much simpler:

    This will produce the same results as the complex "Refined Query" above.

    You can also apply further conditions when querying the view:

    Output (example structure, showing those at least 5 minutes short):

    • Simplifying Complex Queries: As demonstrated, views hide complex joins and calculations.

    • Restricting Data Access (Column-Level Security): Views can expose only a subset of columns from underlying tables, preventing users or applications from seeing sensitive information (e.g., Home_Address, Home_Phone were not included in our Employee_Tardiness view).

    Views offer a powerful way to:

    • Simplify data access: Make complex queries easier to write and understand.

    • Abstract database logic: Separate application code from the complexities of the database schema.

    • Enhance security: Control access to specific rows and columns.

    • — the full reference for CREATE VIEW, ALTER VIEW, DROP VIEW, and updatable views

    This page is licensed: CC BY-SA / Gnu FDL

    Backup and Restore Overview

    Complete MariaDB backup and recovery guide. Complete resource for backup methods, mariabackup usage, scheduling, and restoration for production use.

    This article briefly discusses the main ways to backup MariaDB. For detailed descriptions and syntax, see the individual pages. More detail is in the process of being added.

    Logical vs Physical Backups

    Logical backups consist of the SQL statements necessary to restore the data, such as CREATE DATABASE, CREATE TABLE and INSERT.

    Physical backups are performed by copying the individual data files or directories.

    The main differences are as follows:

    • logical backups are more flexible, as the data can be restored on other hardware configurations, MariaDB versions or even on another DBMS, while physical backups cannot be imported on significantly different hardware, a different DBMS, or potentially even a different MariaDB version.

    • logical backups can be performed at the level of database and table, while physical databases are the level of directories and files. In the and storage engines, each table has an equivalent set of files.

    • logical backups are larger in size than the equivalent physical backup.

    • logical backups takes more time to both backup and restore than the equivalent physical backup.

    • log files and configuration files are not part of a logical backup

    The mariadb-backup program is a physical online backup tool and a fork of Percona XtraBackup with added support for compression and data-at-rest encryption.

    MariaDB Backup creates a file-level backup of data from the MariaDB Server data directory. This backup includes temporal data, and the encrypted and unencrypted tablespaces of supported storage engines (e.g., InnoDB, MyRocks, Aria).

    MariaDB Server implements:

    • Full backups, which contain all data in the database.

    • Incremental backups, which contain modifications since the last backup.

    • Partial backups, which contain a subset of the tables in the database.

    Backup support is specific to storage engines. All supported storage engines enable full backup. The InnoDB storage engine additionally supports incremental backup.

    A feature of MariaDB Backup and MariaDB Server, non-blocking backups minimize workload impact during backups. When MariaDB Backup connects to MariaDB Server, staging operations are initiated to protect data during read.

    Non-blocking backup functionality differs from historical backup functionality in the following ways:

    • MariaDB Backup includes optimizations to backup staging, including DDL statement tracking, which reduces lock-time during backups.

    • MariaDB Backup in MariaDB Community Server 10.4 and later will block writes, log tables, and statistics.

    • Older releases used FLUSH TABLES WITH READ LOCK, which closed open tables and only allowed tables to be reopened with a read lock during the duration of backups.

    Full backups produced using MariaDB Server are not initially point-in-time consistent, and an attempt to restore from a raw full backup will cause InnoDB to crash to protect the data. Incremental backups contain only the changes since the last backup and cannot be used standalone to perform a restore.

    To restore from a backup, you first need to prepare the backup for point-in-time consistency using the --prepare command:

    • Running --prepare on a full backup synchronizes the tablespaces, ensuring they are point-in-time consistent.

    • Running --prepare on an incremental backup synchronizes the tablespaces and applies the updated data into the previous full backup.

    • Running --prepare

    For MariaDB Backup to safely restore data from full and incremental backups, the data directory must be empty. When MariaDB Backup restores from a backup using --copy-back or --move-back, it copies or moves the backup files into the MariaDB Server data directory.

    When MariaDB Backup performs a backup operation, it connects to the running MariaDB Server to manage locks and backup staging that prevent the Server from writing to a file while being read. It is recommended that a dedicated user be created and authorized to perform backups:

    (previously mysqldump) performs a logical backup. It is the most flexible way to perform a backup and restore, and a good choice when the data size is relatively small.

    For large datasets, the backup file can be large, and the restore time lengthy.

    mariadb-dump dumps the data into SQL format (it can also dump into other formats, such as CSV or XML) which can then easily be imported into another database. The data can be imported into other versions of MariaDB, MySQL, or even another DBMS entirely, assuming there are no version or DBMS-specific statements in the dump.

    mariadb-dump dumps triggers along with tables, as these are part of the table definition. However, , , and are not, and need extra parameters to be recreated explicitly (for example, --routines and --events). and are however also part of the system tables (for example ).

    InnoDB uses the , which stores data and indexes from its tables in memory. This buffer is very important for performance. If InnoDB data doesn't fit the memory, it is important that the buffer contains the most frequently accessed data. However, last accessed data is candidate for insertion into the buffer pool. If not properly configured, when a table scan happens, InnoDB may copy the whole contents of a table into the buffer pool. The problem with logical backups is that they always imply full table scans.

    An easy way to avoid this is by increasing the value of the system variable. It represents the number of milliseconds that must pass before a recently accessed page can be put into the "new" sublist in the buffer pool. Data which is accessed only once should remain in the "old" sublist. This means that they will soon be evicted from the buffer pool. Since during the backup process the "old" sublist is likely to store data that is not useful, one could also consider resizing it by changing the value of the system variable.

    It is also possible to explicitly dump the buffer pool on disk before starting a logical backup, and restore it after the process. This will undo any negative change to the buffer pool which happens during the backup. To dump the buffer pool, the system variable can be set to ON. To restore it, the system variable can be set to ON.

    Backing up a single database

    Restoring or loading the database

    See the page for detailed syntax and examples.

    performs a physical backup, and works only for backing up and tables. It can only be run on the same machine as the location of the database directories.

    Percona XtraBackup is not supported in MariaDB. is the recommended backup method to use instead of Percona XtraBackup. See for more information.

    is a tool for performing fast, hot backups. It was designed specifically for databases, but can be used with any storage engine (although not with and ). It is not included with MariaDB.

    Some filesystems, like Veritas, support snapshots. During the snapshot, the table must be locked. The proper steps to obtain a snapshot are:

    • From the client, execute . The client must remain open.

    • From a shell, execute mount vxfs snapshot

    • The client can execute .

    Widely-used physical backup method, using a Perl script as a wrapper.

    Besides the system utilities, it is possible to use third-party GUI tools to perform backup and restore operations. In this context, it is worth mentioning dbForge Studio for MySQL, a feature-rich database IDE that is fully compatible with MariaDB and delivers extensive backup functionality.

    The backup and restore module of the Studio allows precise up to particular database objects. The feature of scheduling regular backups offers specific settings to handle errors and keep a log of them. Additionally, settings and configurations can be saved for later reuse.

    These operations are wizard-aided allowing users to set up all tasks in a visual mode.

    • • blog post • 2015 • 5 minutes read

    This page is licensed: CC BY-SA / Gnu FDL

    Encrypted Files Backup (mariadb-backup)

    How mariadb-backup backs up and restores encrypted data files.

    This page addresses a major misconception: Many users assume that, because mariadb-backup reads encrypted files, it "unlocks" them. However, the encryption remains intact throughout the entire lifecycle, as explained in the following.

    Compatibility with Data-at-Rest Encryption (TDE)

    While this page primarily discusses using external tools like openssl to encrypt a backup stream, mariadb-backup is also fully compatible with MariaDB's internal data-at-rest encryption (TDE) for InnoDB and Aria tables.

    When backing up a server where encryption is enabled, there are specific behaviors and requirements during the backup, prepare, and restore phases.

    1. The Backup Phase

    When mariadb-backup performs a backup, it copies the physical files exactly as they exist on disk. If the files are encrypted at rest by the MariaDB server, the backup files remain encrypted.

    • No "double encryption" required: You do not need to pipe the backup through openssl to secure it, as the data is already encrypted. However, you may still choose to do so for additional security or to encrypt non-InnoDB files (like configuration files or metadata).

    • Key Access: mariadb-backup must be able to read the encrypted files. In order to do that, mariadb-backup queries the server as to what encryption plugin is used:

    Once mariadb-backup knows that file_key_management is used, it queries the server for details, like the location of the key file, and which encryption algorithm is used:

    mariadb-backup uses that information to calculate the checksums of .ibd files/pages, and to decrypt the redo log for further information.

    The "Prepare" phase is when mariadb-backup makes the data consistent by applying the redo logs.

    • Requirement: To perform the prepare phase, the tool must have access to the same encryption keys used by the server at the time of the backup.

    • Persistence: After the prepare phase is complete, the data files remain encrypted. The tool does not "decrypt" the database into plain text; it only ensures the encrypted pages are consistent.

    The restore phase simply moves the encrypted files back to the target server's data directory.

    To ensure a restorable backup of an encrypted MariaDB instance, you must:

    1. Access to encryption information: Ensure that mariadb-backup has the same access to encryption information as the server does.

    2. Back up the keys: The encryption keys themselves are not stored inside the backup. You must manually back up your keyfile.txt, AWS KMS credentials, or HashiCorp Vault tokens separately.

    3. Synchronize target keys:

    • Data State: Encrypted at source → Encrypted in backup → Encrypted at destination.

    • Prepare Phase: Needs the key to read/apply logs, but writes encrypted data back out.

    • Restoration: If you lose your keys, your backup is permanently unrecoverable.

    Mixed-encryption backups are a common scenario, especially in large production environments where a full "rotation" (encrypting all old data) can take days or weeks.

    mariadb-backup is "smart" enough to handle a mixed-state tablespace.

    When you run a backup on a mixed-encryption database, here is exactly what happens under the hood:

    mariadb-backup reads the header of every tablespace file (.ibd files). Each header contains metadata that tells the tool whether that specific file is encrypted or plain text.

    • If the header says "Encrypted," the tool uses the configured KMS keys to read the pages.

    • If the header says "Plain Text," it reads them normally.

    The backup is an exact physical replica. This means:

    • Table A (Encrypted) stays encrypted in the backup.

    • Table B (Unencrypted) stays unencrypted in the backup. The backup does not "standardize" the encryption; it respects the individual state of each table at the exact moment the backup started.

    This is where the KMS configuration is vital. During the "Prepare" phase (--prepare), mariadb-backup applies the Redo Log to the tables to ensure consistency.

    • If a transaction in the Redo Log involves an encrypted table, the tool uses the keys to apply that change.

    • If the transaction involves an unencrypted table, it applies it without keys.

    • The Result: After the prepare phase, your backup remains in a mixed state, exactly matching the original source.

    Scenario
    Behavior
    Risk

    In many production environments, a database may contain a mix of encrypted and unencrypted tables. This occurs frequently during a rolling migration to TDE or when only specific sensitive tables are targeted for encryption.

    mariadb-backup detects the encryption status of each tablespace individually by reading the file headers. It does not "force" encryption on unencrypted tables, nor does it decrypt encrypted ones. The backup is an exact physical replica of the source's mixed state.

    Even if only one table in your database is encrypted, the entire --prepare phase requires the Key Management System (KMS) to be active and configured. The tool must be able to read the encryption keys to apply redo logs and ensure consistency across the entire dataset. If the KMS is unavailable, the prepare phase fails.

    Because a mixed-state backup leaves unencrypted tables (and database metadata) vulnerable in the backup file, it is a recommended best practice to use Layered Encryption.

    By piping the mariadb-backup stream through an external encryption tool (like OpenSSL), you ensure that:

    • Legacy/Unencrypted tables are protected within the backup archive.

    • Metadata (file names, schemas, and logs) is hidden.

    • Transport Security is maintained regardless of the destination server's TDE configuration.

    Component
    State in Backup
    Requires KMS for Prepare?

    DROP TABLE

    Complete DROP TABLE syntax: TEMPORARY, IF EXISTS, WAIT/NOWAIT, RESTRICT/CASCADE options, metadata locks, atomic DROP, and replication behavior.

    Syntax

    DROP [TEMPORARY] TABLE [IF EXISTS] [/*COMMENT TO SAVE*/]
        tbl_name [, tbl_name] ...
        [WAIT n|NOWAIT]
        [RESTRICT | CASCADE]

    Description

    DROP TABLE removes one or more tables. You must have the DROP privilege for each table. All table data and the table definition are removed, as well as triggers associated to the table, so be careful with this statement! If any of the tables named in the argument list do not exist, MariaDB returns an error indicating by name which non-existing tables it was unable to drop, but it also drops all of the tables in the list that do exist.

    Important: When a table is dropped, user privileges on the table are not automatically dropped. See GRANT.

    If another thread is using the table in an explicit transaction or an autocommit transaction, then the thread acquires a metadata lock (MDL) on the table. The DROP TABLE statement will wait in the "Waiting for table metadata lock" thread state until the MDL is released. MDLs are released in the following cases:

    • If an MDL is acquired in an explicit transaction, then the MDL will be released when the transaction ends.

    • If an MDL is acquired in an autocommit transaction, then the MDL will be released when the statement ends.

    • Transactional and non-transactional tables are handled the same.

    Note that for a partitioned table, DROP TABLE permanently removes the table definition, all of its partitions, and all of the data which was stored in those partitions. It also removes the partitioning definition (.par) file associated with the dropped table.

    For each referenced table, DROP TABLE drops a temporary table with that name, if it exists. If it does not exist, and the TEMPORARY keyword is not used, it drops a non-temporary table with the same name, if it exists. The TEMPORARY keyword ensures that a non-temporary table will not accidentally be dropped.

    Use IF EXISTS to prevent an error from occurring for tables that do not exist. A NOTE is generated for each non-existent table when usingIF EXISTS. See .

    If a references this table, the table cannot be dropped. In this case, it is necessary to drop the foreign key first.

    RESTRICT and CASCADE are allowed to make porting from other database systems easier. In MariaDB, they do nothing.

    The comment before the table names (/*COMMENT TO SAVE*/) is stored in the . That feature can be used by replication tools to send their internal messages.

    It is possible to specify table names as db_name.tab_name. This is useful to delete tables from multiple databases with one statement. See for details.

    The is required to use DROP TABLE on non-temporary tables. For temporary tables, no privilege is required, because such tables are only visible for the current session.

    Note: DROP TABLE automatically commits the current active transaction, unless you use the TEMPORARY keyword.

    DROP TABLE reliably deletes table remnants inside a storage engine even if the .frm file is missing.

    DROP TABLE does not reliably delete table remnants inside a storage engine even if the .frm file is missing. A missing .frm file will result in the statement failing.

    Set the lock wait timeout. See .

    DROP TABLE has the following characteristics in :

    • DROP TABLE IF EXISTS are always logged.

    • DROP TABLE without IF EXISTS for tables that don't exist are not written to the .

    • Dropping of TEMPORARY

    DROP TABLE on the primary is treated on the replica as DROP TABLE IF EXISTS. You can change that by setting to STRICT.

    if the is killed during an , you may find a table named #sql-... in your data directory. These temporary tables will always be deleted automatically.

    If you want to delete one of these tables explicitly you can do so by using the following syntax:

    When running an ALTER TABLE…ALGORITHM=INPLACE that rebuilds the table, InnoDB will create an internal #sql-ib table.

    The same name as the .frm file is used for the intermediate copy of the table. The #sql-ib names are used by TRUNCATE and delayed DROP.

    The best way to drop all tables in a database is by executing , which will drop the database itself, and all tables in it.

    However, if you want to drop all tables in the database, but you also want to keep the database itself and any other non-table objects in it, then you would need to execute DROP TABLE to drop each individual table. You can construct these DROP TABLE commands by querying the table in the database. For example:

    MariaDB starting with

    DROP TABLE for a single table is atomic () for most engines, including InnoDB, MyRocks, MyISAM and Aria. This means that if there is a crash (server down or power outage) during DROP TABLE, all tables that have been processed so far will be completely dropped, including related trigger files and status entries, and the will include a DROP TABLE statement for the dropped tables. Tables for which the drop had not started will be left intact.DROP TABLE was extended to be able to delete a table that was only partly dropped (), as explained above. Atomic DROP TABLE is the final piece to make DROP TABLE fully reliable. Dropping multiple tables is crash-safe. See for more information.

    There is a small chance that, during a server crash happening in the middle of

    Beware that DROP TABLE can drop both tables and . This is mainly done to allow old tools like (previously mysqldump) to work with sequences.

    This page is licensed: GPLv2, originally from

    Copying Tables Between Databases and Servers

    This guide explains various methods for copying tables between MariaDB databases and servers, including using FLUSH TABLES FOR EXPORT and mysqldump.

    With MariaDB it's very easy to copy tables between different MariaDB databases and different MariaDB servers. This works for tables created with the Archive, Aria, CSV, InnoDB, MyISAM, MERGE, and XtraDB engines.

    The normal procedures to copy a table is:

    FLUSH TABLES db_name.table_name FOR EXPORT
    
    # Copy the relevant files associated with the table
    
    UNLOCK TABLES;

    The table files can be found in datadir/databasename (you can executeSELECT @@datadir to find the correct directory). When copying the files, you should copy all files with the same table_name + various extensions. For example, for an Aria table of name foo, you will have files foo.frm, foo.MAI, foo.MAD and possibly foo.TRG if you have triggers.

    If one wants to distribute a table to a user that doesn't need write access to the table and one wants to minimize the storage size of the table, the recommended engine to use is Aria or MyISAM as one can pack the table with aria_pack or myisampack respectively to make it notablly smaller. MyISAM is the most portable format as it's not dependent on whether the server settings are different. Aria and InnoDB require the same block size on both servers.

    The following storage engines support export without FLUSH TABLES ... FOR EXPORT, assuming the source server is down and the receiving server is not accessing the files during the copy.

    Engine
    Comment

    For all of the above storage engines (Archive, Aria, CSV, MyISAM and MERGE), one can copy tables even from a live server under the following circumstances:

    • You have done a FLUSH TABLES or FLUSH TABLE table_name for the specific table.

    • The server is not accessing the tables during the copy process.

    The advantage of is that the table is read locked until is executed.

    Warning: If you do the above live copy, you are doing this on your own risk as if you do something wrong, the copied table is very likely to be corrupted. The original table will of course be fine.

    If you want to give a user access to some data in a table for the user to use in their MariaDB server, you can do the following:

    First let's create the table we want to export. To speed up things, we create this without any indexes. We use TRANSACTIONAL=0 ROW_FORMAT=DYNAMIC for Aria to use the smallest possible row format.

    Then we pack it and generate the indexes. We use a big sort buffer to speed up generating the index.

    The procedure for MyISAM tables is identical, except that doesn't have the --ignore-control-file option.

    InnoDB's file-per-table tablespaces are transportable, which means that you can copy a file-per-table tablespace from one MariaDB Server to another server. See for more information.

    Tables that use most storage engines are immediately usable when their files are copied to the new .

    However, this is not true for tables that use . InnoDB tables have to be imported with . See for more information.

    • - Compressing the MyISAM data file for easier distribution.

    This page is licensed: CC BY-SA / Gnu FDL

    mariadb-backup and BACKUP STAGE

    Understand backup locking stages. This page explains how mariadb-backup uses BACKUP STAGE statements to minimize locking during operation.

    mariadb-backup was previously called mariabackup.

    The BACKUP STAGE statements make it possible to make an efficient external backup tool. How mariadb-backup uses these statements depends on whether you are using the version that is bundled with MariaDB Community Server or the version that is bundled with MariaDB Enterprise Server.

    For a complete list of mariadb-backup options, .

    For a detailed description of mariadb-backup functionality, .

    BACKUP STAGE in MariaDB Community Server

    The BACKUP STAGE statements are supported. However, the version of mariadb-backup that is bundled with MariaDB Community Server does not yet use the BACKUP STAGE statement in the most efficient way. mariadb-backup simply executes the following BACKUP STAGE statement to lock the database:

    BACKUP STAGE START;
    BACKUP STAGE BLOCK_COMMIT;

    When the backup is complete, it executes the following BACKUP STAGE statement to unlock the database:

    • Copy some transactional tables.

      • InnoDB (i.e. ibdataN and file extensions .ibd and .isl)

    • Copy the tail of some transaction logs.

    mariadb-backup from MariaDB Community Server does not perform any tasks in the START stage.

    mariadb-backup from MariaDB Community Server does not currently perform any tasks in the FLUSH stage.

    mariadb-backup from MariaDB Community Server does not currently perform any tasks in the BLOCK_DDL stage.

    mariadb-backup from MariaDB Community Server performs the following tasks in the BLOCK_COMMIT stage:

    • Copy other files.

      • i.e. file extensions .frm, .isl, .TRG, .TRN, .opt, .par

    mariadb-backup from MariaDB Community Server performs the following tasks in the END stage:

    • Copy the MyRocks checkpoint into the backup.

    The following sections describe how the MariaDB Backup version of mariadb-backup that is bundled with MariaDB Enterprise Server uses each statement in an efficient way.

    mariadb-backup from MariaDB Enterprise Server performs the following tasks in the START stage:

    • Copy all transactional tables.

      • InnoDB (i.e. ibdataN and file extensions .ibd and .isl)

      • Aria (i.e.

    mariadb-backup from MariaDB Enterprise Server performs the following tasks in the FLUSH stage:

    • Copy all non-transactional tables that are not in use. This list of used tables is found with SHOW OPEN TABLES.

      • MyISAM (i.e. file extensions .MYD and .MYI)

    mariadb-backup from MariaDB Enterprise Server performs the following tasks in the BLOCK_DDL stage:

    • Copy other files.

      • i.e. file extensions .frm, .isl, .TRG, .TRN, .opt, .par

    mariadb-backup from MariaDB Enterprise Server performs the following tasks in the BLOCK_COMMIT stage:

    • Create a MyRocks checkpoint using the rocksdb_create_checkpoint system variable.

    • Copy changes to system log tables.

      • mysql.general_log

    mariadb-backup from MariaDB Enterprise Server performs the following tasks in the END stage:

    • Copy the MyRocks checkpoint into the backup.

    This page is licensed: CC BY-SA / Gnu FDL

    Storage Engines Overview

    An introduction to MariaDB's pluggable storage engine architecture, highlighting key engines like InnoDB, MyISAM, and Aria for different workloads.

    Overview

    MariaDB features pluggable storage engines to allow per-table workload optimization.

    A storage engine is a type of plugin for MariaDB:

    • Different storage engines may be optimized for different workloads, such as transactional workloads, analytical workloads, or high throughput workloads.

    • Different storage engines may be designed for different use cases, such as federated table access, table sharding, and table archiving in the cloud.

    • Different tables on the same server may use different storage engines.

    Engine
    Target
    Optimization
    Availability

    Identify the server's global default storage engine by using to query the system variable:

    Identify the session's default storage engine by using :

    Global default storage engine:

    Session default storage engine supersedes global default during this session:

    Storage engine is specified at time of table creation using a ENGINE = parameter.

    Standard MariaDB storage engines are used for System Table storage:

    • Yes, different tables can use different storage engines on the same server.

    • To create a table with a specific storage engine, specify the ENGINE table option to the statement.

    • Yes, a single query can reference tables that use multiple storage engines.

    • In some cases, special configuration may be required. For example, ColumnStore requires cross engine joins to be configured.

    • is the recommended storage engine for transactional or OLTP workloads.

    • is the recommended storage engine for analytical or OLAP workloads.

    An application that performs both transactional and analytical queries is known as .

    HTAP can be implemented with MariaDB by using for transactional queries and for analytical queries.

    • .

    • , which shows available storage engines.

    • , which shows storage engine by table.

    This page is: Copyright © 2025 MariaDB. All rights reserved.

    Aria Storage Engine

    An overview of Aria, a storage engine designed as a crash-safe alternative to MyISAM, featuring transactional capabilities and improved caching.

    The Aria storage engine is compiled in by default from and it is required to be 'in use' when MariaDB is started.

    All system tables are Aria.

    Additionally, internal on-disk tables are in the Aria table format instead of the MyISAM table format. This should speed up some GROUP BY and DISTINCT queries because Aria has better caching than MyISAM.

    Note: The Aria storage engine was previously called Maria (see The Aria Name for details on the rename) and in previous versions of MariaDB the engine was still called Maria.

    The following table options to Aria tables in CREATE TABLE and ALTER TABLE:

    • TRANSACTIONAL= 0 | 1 : If the TRANSACTIONAL table option is set for an Aria table, then the table are crash-safe. This is implemented by logging any changes to the table to Aria's transaction log, and syncing those writes at the end of the statement. This will marginally slow down writes and updates. However, the benefit is that if the server dies before the statement ends, all non-durable changes will roll back to the state at the beginning of the statement. This also needs up to 6 bytes more for each row and key to store the transaction id (to allow concurrent insert's and selects).

      • TRANSACTIONAL=1 is not supported for partitioned tables.

    • PAGE_CHECKSUM= 0 | 1 : If index and data should use page checksums for extra safety.

    • TABLE_CHECKSUM= 0 | 1 : Same as CHECKSUM in MySQL 5.1

    • ROW_FORMAT=PAGE | FIXED | DYNAMIC : The table's .

      • The default value is PAGE.

      • To emulate MyISAM, set ROW_FORMAT=FIXED or ROW_FORMAT=DYNAMIC

    The TRANSACTIONAL and ROW_FORMAT table options interact as follows:

    • If TRANSACTIONAL=1 is set, then the only supported row format is PAGE. If ROW_FORMAT is set to some other value, then Aria issues a warning, but still forces the row format to be PAGE.

    • If TRANSACTIONAL=0 is set, then the table are not be crash-safe, and any row format is supported.

    Some other improvements are:

    • now ignores values in NULL fields. This makes CHECKSUM TABLE faster and fixes some cases where same table definition could give different checksum values depending on . The disadvantage is that the value is now different compared to other MySQL installations. The new checksum calculation is fixed for all table engines that uses the default way to calculate and MyISAM which does the calculation internally. Note: Old MyISAM tables with internal checksum returns the same checksum as before. To fix them to calculate according to new rules you have to do an . You can use the old ways to calculate checksums by using the option --old to mariadbdmysqld or set the system variable '@@old' to 1 when you do CHECKSUM TABLE ... EXTENDED;

    For a full list, see .

    In normal operations, the only variables you have to consider are:

      • This is where all index and data pages are cached. The bigger this is, the faster Aria will work.

    aria_log_control file is a very short log file (52 bytes) that contains the current state of all Aria tables related to logging and checkpoints. In particular, it contains the following information:

    • The uuid is a unique identifier per system. All Aria files created will have a copy of this in their .MAI headers. This is mainly used to check if someone has copied an Aria file between MariaDB servers.

    • last_checkpoint_lsn and last_log_number are information about the current aria_log files.

    aria_log.* files contain the log of all operations that change Aria files (including create table, drop table, insert etc..) This is a 'normal' WAL (Write Ahead Log), similar to the InnoDB log file, except that aria_logs contain both redo and undo. Old aria_log files are automatically deleted when they are not needed anymore (Neither the last checkpoint or any running transaction need to refer to the old data anymore).

    The error Missing valid id at start of file. File is not a valid aria control file means that something overwrote at least the first 4 bytes in the file. This can happen due to a problem with the file system (hardware or software), or a bug in which a thread inside MariaDB wrote on the wrong file descriptor (in which case you should , attaching a copy of the control file to assist).

    In the case of a corrupted log file, with the server shut down, one should be able to fix that by deleting all aria_log files. If the control_file is corrupted, then one has to delete the aria_control_file and all aria_log.* files. The effect of this is that on table open of an Aria table, the server will think that it has been moved from another system and do an automatic check and repair of it. If there was no issues, the table are opened and can be used as normal. See also .

    This page is licensed: CC BY-SA / Gnu FDL

    Altering Tables Guide

    Learn how to modify existing table structures using the ALTER TABLE statement, including adding columns, changing types, and managing indexes.

    This guide provides essential instructions for modifying existing table structures. Learn how to add, drop, and change columns, manage indexes and default values, and rename tables, along with key precautions for these operations when working with your database.

    Before making any structural changes to a table, especially if it contains data, always create a backup. The utility is a common and effective tool for this.

    Example: Backing up a single table

    Suppose you have a database db1 and a table clients. Its initial structure is:

    To back up the clients table from the command-line:

    Importing Data Guide

    Learn how to efficiently import data into MariaDB tables from external files using the LOAD DATA INFILE statement.

    This guide introduces methods and tools for efficiently importing bulk data into MariaDB. Learn to prepare your data, use LOAD DATA INFILE and the mariadb-import utility, handle common data import challenges, and manage potential constraints.

    The most common approach for bulk importing is to use a delimited text file.

    1. Export Source Data: Load your data in its original software (e.g., MS Excel, MS Access) and export it as a delimited text file.

    Getting Started with Indexes Guide

    Definitive MariaDB indexes guide: PRIMARY KEY, UNIQUE INDEX, INDEX, FULLTEXT types, CREATE/ALTER TABLE syntax, CREATE INDEX, SHOW INDEX, and EXPLAIN.

    This guide explains the different types of indexes in MariaDB, their characteristics, and how they are used. Learn to create and manage Primary Keys, Unique Indexes, and Plain Indexes, along with key considerations for choosing and maintaining effective indexes for optimal query performance.

    In MariaDB, the terms KEY and INDEX are generally used interchangeably in SQL statements. For a gentler conceptual overview, see .

    There are four main kinds of indexes:

    • Primary Keys:

    Basic Queries

    This guide covers the fundamentals of creating database structures, inserting data, and retrieving information using the default MariaDB client.

    MariaDB is a database system, a database server. To interface with the MariaDB server, you can use a client program, or you can write a program or script with one of the popular programming languages (e.g., PHP) using an API (Application Programming Interface) to interface with the MariaDB server. For the purposes of this article, we will focus on using the default client that comes with MariaDB called mariadb. With this client, you can either enter queries from the command-line, or you can switch to a terminal, that is to say, monitor mode. To start, we'll use the latter.

    From the Linux command-line, you would enter the following to log in as the root user and to enter monitor mode:

    The -u option is for specifying the user name. You would replace root

    Files Created by mariadb-backup

    Reference of files generated during backup. This page explains the purpose of metadata files like xtrabackup_checkpoints created by the tool.

    mariadb-backup creates the following files:

    During the backup, any server options relevant to mariadb-backup are written to the backup-my.cnf option file, so that they can be re-read later during the --prepare stage.

    mariadb-backup creates an empty InnoDB redo log file called ib_logfile0 as part of the --prepare

    INSERT DELAYED
    Implementing Row-Level Security: A view can include a WHERE clause that filters rows based on the user querying it or other criteria, effectively providing row-level access control. For updatable views, defining them with WITH CHECK OPTION (or the similar effect of a CASCADE clause mentioned in original text, usually WITH CASCADED CHECK OPTION) can ensure that INSERTs or UPDATEs through the view adhere to the view's WHERE clause conditions.
  • Preemptive Optimization: Complex, frequently used queries can be defined as views with optimal join strategies and indexing considerations. Other users or applications query the already optimized view, reducing the risk of running inefficient ad-hoc queries.

  • Abstracting Table Structures: Views provide a consistent interface to applications even if the underlying table structures change (e.g., tables are normalized, split, or merged). The view definition can be updated to map to the new structure, while applications continue to query the unchanged view.

  • Improve maintainability: Changes to underlying tables can often be managed by updating the view definition without altering application queries.

    Setup: Example Employee Database

    Building a Complex Query (Example: Employee Tardiness)

    Creating and Using a View

    Other Benefits and Uses of Views

    Summary of View Advantages

    See Also

    CREATE VIEW
    Views
    More Advanced Joins
    spinner
    on data used for a
    partial restore
    requires the
    --export
    option to create the necessary
    .cfg
    files.
    Copy the snapshot files.
  • From a shell, unmount the snapshot with umount snapshot.

  • Backup Tools

    mariadb-backup

    Storage Engines and Backup Types

    Non-Blocking Backups

    Understanding Recovery

    Restore Requires Empty Data Directory

    Creating the Backup User

    While MariaDB Backup requires a user for backup operations, no user is required for restore operations since restores occur while MariaDB Server is not running.

    mariadb-dump

    InnoDB Logical Backups

    mariadb-dump Examples

    mariadb-hotcopy

    mariadb-hotcopy Examples

    Percona XtraBackup

    Filesystem Snapshots

    LVM

    LVM snapshots are not a standalone DBMS backup solution. LVM operates at the block level, meaning it is "database-blind." It captures a crash-consistent state, identical to a sudden power failure, ignoring data cached in RAM. Without flushing buffers and locking tables, snapshots risk torn pages and permanent corruption. Furthermore, the Copy-on-Write (CoW) mechanism significantly degrades production performance. Snapshots also exist on the same physical disks; they are not true backups and offer no protection against hardware failure. Always use application-aware tools (like mariadb-backup) to ensure data integrity.

    dbForge Studio for MySQL

    See Also

    MyISAM
    InnoDB
    mariadb-dump
    stored procedures
    views
    events
    Procedures
    functions
    mysql.proc
    buffer pool
    innodb_old_blocks_time
    innodb_old_blocks_pct
    innodb_buffer_pool_dump_now
    innodb_buffer_pool_load_now
    mariadb-dump
    mariadb-hotcopy
    MyISAM
    ARCHIVE
    mariadb-backup
    Percona XtraBackup Overview: Compatibility with MariaDB
    Percona XtraBackup
    XtraDB/InnoDB
    encryption
    compression
    mariadb
    FLUSH TABLES WITH READ LOCK
    UNLOCK TABLES
    configuration and management of full and partial backups
    Streaming MariaDB backups in the cloud
    spinner
    Before running
    mariadb-backup --copy-back
    , verify that the destination server’s configuration points to the identical keys used during the backup.

    Restore Target

    You restore to a server without a KMS plugin.

    The unencrypted tables work fine, but the encrypted tables are unreadable/corrupted.

    Aria System Tables

    Encrypted (if configured)

    Yes

    Binary / Redo Logs

    Encrypted (if configured)

    Yes

    Backup Metadata

    Plaintext

    No

    Missing Keys

    The backup fails or the prepare phase crashes when it hits the first encrypted table.

    Even if 99% of your tables are unencrypted, 1 encrypted table requires the KMS to be active for the backup to be valid.

    New Tables

    If you enable encryption during a long-running backup, mariadb-backup handles it via the Redo Log.

    Ensure the key used for the new table is the same one available to the backup tool.

    Encrypted InnoDB Table

    Encrypted

    Yes

    Plaintext InnoDB Table

    Plaintext

    2. The Prepare Phase

    3. The Restore Phase

    CRITICAL LIMITATION: A restore is only successful if the target server is configured with the exact same keys and KMS method used by the original server. If the target server has a different key or cannot load the key management plugin, the MariaDB service fails to start, or tables are marked as "corrupted" because the engine cannot decrypt the pages.

    TDE Backup Requirements Checklist

    Key Takeaways

    Mixed-Encryption Backups

    1. File-by-File Detection

    2. Preservation of State

    3. The Prepare Phase in a Mixed Environment

    Key Limitations & Risks for Mixed Backups

    Note on Mixed Environments: mariadb-backup supports databases containing a mix of encrypted and unencrypted tables. The tool detects the encryption status of each tablespace individually. However, if even a single table in the backup is encrypted, the entire --prepare process requires access to the Key Management System (KMS). Without valid keys, the tool cannot verify the consistency of encrypted tables, and the backup preparation fails.

    Handling Mixed-Encryption Environments

    1. Tablespace Detection

    2. The Prepare Phase Requirement

    3. Best Practice: Layered Encryption

    Example: Encrypting a Mixed-State Backup Stream

    Warning: When using Layered Encryption, the restoration process requires two sets of credentials: the external password/key to decrypt the stream, and the MariaDB KMS keys to prepare and run the database. Loss of either set renders the backup unrecoverable.

    Summary of TDE Backup Behavior

    Yes (to initialize engine)

    • The tail of the InnoDB redo log (i.e. ib_logfileN files) are copied for InnoDB tables.

    Copy some transactional tables.

    • Aria (i.e. aria_log_control and file extensions .MAD and .MAI)

  • Copy the non-transactional tables.

    • MyISAM (i.e. file extensions .MYD and .MYI)

    • MERGE (i.e. file extensions .MRG)

    • ARCHIVE (i.e. file extensions .ARM and .ARZ)

    • CSV (i.e. file extensions .CSM and .CSV)

  • Create a MyRocks checkpoint using the rocksdb_create_checkpoint system variable.

  • Copy the tail of some transaction logs.

    • The tail of the InnoDB redo log (i.e. ib_logfileN files) are copied for InnoDB tables.

  • Save the binary log position to xtrabackup_binlog_info.

  • Save the Galera Cluster state information to xtrabackup_galera_info.

  • aria_log_control
    and file extensions
    .MAD
    and
    .MAI
    )
  • Copy the tail of all transaction logs.

    • The tail of the InnoDB redo log (i.e. ib_logfileN files) are copied for InnoDB tables.

    • The tail of the Aria redo log (i.e. aria_log.N files) are copied for Aria tables.

  • MERGE (i.e. file extensions .MRG)
  • ARCHIVE (i.e. file extensions .ARM and .ARZ)

  • CSV (i.e. file extensions .CSM and .CSV)

  • Copy the tail of all transaction logs.

    • The tail of the InnoDB redo log (i.e. ib_logfileN files) are copied for InnoDB tables.

    • The tail of the Aria redo log (i.e. aria_log.N files) are copied for Aria tables.

  • Copy the non-transactional tables that were in use during BACKUP STAGE FLUSH.

    • MyISAM (i.e. file extensions .MYD and .MYI)

    • MERGE (i.e. file extensions .MRG)

    • ARCHIVE (i.e. file extensions .ARM and .ARZ)

    • CSV (i.e. file extensions .CSM and .CSV)

  • Check ddl.log for DDL executed before the BLOCK DDL stage.

    • The file names of newly created tables can be read from ddl.log.

    • The file names of dropped tables can also be read from ddl.log.

    • The file names of renamed tables can also be read from ddl.log, so the files can be renamed instead of re-copying them.

  • Copy changes to system log tables.

    • mysql.general_log

    • mysql.slow_log

    • This is easy as these are append only.

  • Copy the tail of all transaction logs.

    • The tail of the InnoDB redo log (i.e. ib_logfileN files) are copied for InnoDB tables.

    • The tail of the Aria redo log (i.e. aria_log.N files) are copied for Aria tables.

  • mysql.slow_log
  • This is easy as these are append only.

  • Copy changes to statistics tables.

    • mysql.table_stats

    • mysql.column_stats

    • mysql.index_stats

  • Copy the tail of all transaction logs.

    • The tail of the InnoDB redo log (i.e. ib_logfileN files) are copied for InnoDB tables.

    • The tail of the Aria redo log (i.e. aria_log.N files) are copied for Aria tables.

  • Save the binary log position to xtrabackup_binlog_info.

  • Save the Galera Cluster state information to xtrabackup_galera_info.

  • To use a version of mariadb-backup that uses the BACKUP STAGE statements in the most efficient way, use MariaDB Backup bundled with MariaDB Enterprise Server.

    Tasks Performed Prior to BACKUP STAGE in MariaDB Community Server

    BACKUP STAGE START in MariaDB Community Server

    BACKUP STAGE FLUSH in MariaDB Community Server

    BACKUP STAGE BLOCK_DDL in MariaDB Community Server

    BACKUP STAGE BLOCK_COMMIT in MariaDB Community Server

    BACKUP STAGE END in MariaDB Community Server

    BACKUP STAGE in MariaDB Enterprise Server

    BACKUP STAGE START in MariaDB Enterprise Server

    BACKUP STAGE FLUSH in MariaDB Enterprise Server

    BACKUP STAGE BLOCK_DDL in MariaDB Enterprise Server

    BACKUP STAGE BLOCK_COMMIT in MariaDB Enterprise Server

    BACKUP STAGE END in MariaDB Enterprise Server

    BACKUP STAGE
    spinner
    see this page
    see this page

    To listen on all available IPv4 interfaces: Comment it out entirely (#bind-address = 127.0.0.1) or set bind-address = 0.0.0.0.

  • To listen on a specific public IP address of your server: bind-address = <your_server_public_ip>.

  • Alternatively, to effectively disable binding to a specific address and listen on all, you can add skip-bind-address. Example changes:

  • Or, to be explicit for listening on all interfaces if bind-address was previously restrictive:

    Username

  • Host (IP address, hostname, or subnet with wildcards like %)

  • Password (using IDENTIFIED BY 'password')

  • with a strong, unique password.
    Starting and Stopping MariaDB
    GRANT

    Replace 'your_username' and 'your_password' with your actual MariaDB credentials.

  • --add-locks: Locks the table during the backup and unlocks it afterward.

  • db1 clients: Specifies the database and then the table.

  • > clients.sql: Redirects the output to a file named clients.sql.

  • Restoring from a backup

    If you need to restore the table:

    This command uses the mariadb client to execute the SQL in clients.sql, which will typically drop the existing table (if it exists) and recreate it from the backup. Ensure no critical data has been added to the live table since the backup if you intend to overwrite it.

    For the examples that follow, we'll assume structural changes are being made, sometimes on an empty table for simplicity, but the backup step is always recommended for tables with data.

    Use the ALTER TABLE statement with the ADD COLUMN clause.

    Add a column to the end of the table:

    To add a status column with a fixed width of two characters:

    Add a column after a specific existing column:

    To add address2 (varchar 25) after the address column:

    Add a column to the beginning of the table:

    (Assuming new_first_column is the one to be added at the beginning).

    After additions, the table structure might look like (excluding new_first_column for consistency with original example flow):

    Use ALTER TABLE with CHANGE or MODIFY.

    Change column type (e.g., to ENUM):

    The status column name is specified twice even if not changing the name itself when using CHANGE.

    Change column name and keep type:

    To change status to active while keeping the ENUM definition:

    When using CHANGE, the current column name is followed by the new column name and the complete type definition.

    Modify column type or attributes without renaming:

    Use MODIFY if you are only changing the data type or attributes, not the name.

    Complex Changes (e.g., ENUM migration with data):

    Changing ENUM values in a table with existing data requires careful steps to prevent data loss. This typically involves:

    1. Temporarily modifying the ENUM to include both old and new values.

    2. Updating existing rows to use the new values.

    3. Modifying the ENUM again to remove the old values.

    Example of changing address to address1 (40 chars) and preparing active ENUM for new values 'yes','no' from 'AC','IA':

    Then, update the data:

    Finally, restrict the ENUM to new values:

    To remove a column and its data (this action is permanent and irreversible without a backup):

    Set a default value for a column:

    If most clients are in 'LA', set it as the default for the state column:

    Remove a default value from a column:

    This reverts the default to its standard (e.g., NULL if nullable, or determined by data type).

    This DROP DEFAULT does not delete existing data in the column.

    Indexes are separate objects from columns. Modifying an indexed column often requires managing its index.

    View existing indexes on a table with SHOW INDEX:

    The \G displays results in a vertical format, which can be easier to read for wide output.

    Example output:

    Changing an indexed column (e.g., Primary Key):

    Attempting to CHANGE a column that is part of a PRIMARY KEY without addressing the key might result in an error like "Multiple primary key defined". The index must be dropped first, then the column changed, and the key re-added.

    The order is important: DROP PRIMARY KEY first.

    Changing a column with another index type (e.g., UNIQUE):

    If cust_id had a UNIQUE index named cust_id_unique_idx (Key_name from SHOW INDEX):

    If the Key_name is the same as the Column_name (e.g. for a single column UNIQUE key defined on cust_id where cust_id is also its Key_name):

    Changing index type and handling duplicates (e.g., INDEX to UNIQUE):

    If changing from an index type that allows duplicates (like a plain INDEX) to one that doesn't (UNIQUE), and duplicate data exists, the operation will fail. To force the change and remove duplicates (use with extreme caution):

    The IGNORE keyword causes rows with duplicate key values (for the new UNIQUE key) to be deleted. Only the first encountered row is kept.

    Rename a table:

    To change the name of clients to client_addresses:

    Move a table to another database (can be combined with renaming):

    To move client_addresses to a database named db2:

    Re-sort data within a table (MyRocks/Aria, not typically InnoDB):

    For some storage engines (excluding InnoDB where tables are ordered by the primary key), you can physically reorder rows. This does not usually apply to InnoDB unless the ORDER BY columns form the primary key.

    After this, SELECT * FROM client_addresses (without an ORDER BY clause) might return rows in this new physical order, until further data modifications occur.

    • Backup First: Always back up tables before making structural alterations, especially on production systems.

    • Data Integrity: Be mindful of how changes (e.g., type changes, ENUM modifications, dropping columns) can affect existing data. Test changes in a development environment.

    • Irreversible Actions: Operations like DROP COLUMN or DROP TABLE are generally irreversible without restoring from a backup. There's typically no confirmation prompt.

    • Indexes: Understand that indexes are distinct from columns. Modifying indexed columns often requires separate steps to manage the associated indexes.

    • Performance: ALTER TABLE operations on large tables can be time-consuming and resource-intensive, potentially locking the table and impacting application performance. Plan these operations during maintenance windows if possible.

    This page is licensed: CC BY-SA / Gnu FDL

    Before You Begin: Backup Your Tables

    mariadb-dump

    Adding Columns

    Changing Column Definitions

    Dropping Columns

    Managing Default Values

    Managing Indexes

    Renaming and Shifting Tables

    Key Considerations

    spinner
    CREATE TABLE `Employees` (
      `ID` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
      `First_Name` VARCHAR(25) NOT NULL,
      `Last_Name` VARCHAR(25) NOT NULL,
      `Position` VARCHAR(25) NOT NULL,
      `Home_Address` VARCHAR(50) NOT NULL,
      `Home_Phone` VARCHAR(12) NOT NULL,
      PRIMARY KEY (`ID`)
    ) ENGINE=MyISAM;
    
    INSERT INTO `Employees` (`First_Name`, `Last_Name`, `Position`, `Home_Address`, `Home_Phone`)
    VALUES
      ('Mustapha', 'Mond', 'Chief Executive Officer', '692 Promiscuous Plaza', '326-555-3492'),
      ('Henry', 'Foster', 'Store Manager', '314 Savage Circle', '326-555-3847'),
      ('Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456'),
      ('Lenina', 'Crowne', 'Cashier', '281 Bumblepuppy Boulevard', '328-555-2349'),
      ('Fanny', 'Crowne', 'Restocker', '1023 Bokanovsky Lane', '326-555-6329'),
      ('Helmholtz', 'Watson', 'Janitor', '944 Soma Court', '329-555-2478');
    CREATE TABLE `Hours` (
      `ID` TINYINT(3) UNSIGNED NOT NULL,
      `Clock_In` DATETIME NOT NULL,
      `Clock_Out` DATETIME NOT NULL
    ) ENGINE=MyISAM;
    
    INSERT INTO `Hours`
    VALUES ('1', '2005-08-08 07:00:42', '2005-08-08 17:01:36'),
      ('1', '2005-08-09 07:01:34', '2005-08-09 17:10:11'),
      ('1', '2005-08-10 06:59:56', '2005-08-10 17:09:29'),
      ('1', '2005-08-11 07:00:17', '2005-08-11 17:00:47'),
      ('1', '2005-08-12 07:02:29', '2005-08-12 16:59:12'),
      ('2', '2005-08-08 07:00:25', '2005-08-08 17:03:13'),
      ('2', '2005-08-09 07:00:57', '2005-08-09 17:05:09'),
      ('2', '2005-08-10 06:58:43', '2005-08-10 16:58:24'),
      ('2', '2005-08-11 07:01:58', '2005-08-11 17:00:45'),
      ('2', '2005-08-12 07:02:12', '2005-08-12 16:58:57'),
      ('3', '2005-08-08 07:00:12', '2005-08-08 17:01:32'),
      ('3', '2005-08-09 07:01:10', '2005-08-09 17:00:26'),
      ('3', '2005-08-10 06:59:53', '2005-08-10 17:02:53'),
      ('3', '2005-08-11 07:01:15', '2005-08-11 17:04:23'),
      ('3', '2005-08-12 07:00:51', '2005-08-12 16:57:52'),
      ('4', '2005-08-08 06:54:37', '2005-08-08 17:01:23'),
      ('4', '2005-08-09 06:58:23', '2005-08-09 17:00:54'),
      ('4', '2005-08-10 06:59:14', '2005-08-10 17:00:12'),
      ('4', '2005-08-11 07:00:49', '2005-08-11 17:00:34'),
      ('4', '2005-08-12 07:01:09', '2005-08-12 16:58:29'),
      ('5', '2005-08-08 07:00:04', '2005-08-08 17:01:43'),
      ('5', '2005-08-09 07:02:12', '2005-08-09 17:02:13'),
      ('5', '2005-08-10 06:59:39', '2005-08-10 17:03:37'),
      ('5', '2005-08-11 07:01:26', '2005-08-11 17:00:03'),
      ('5', '2005-08-12 07:02:15', '2005-08-12 16:59:02'),
      ('6', '2005-08-08 07:00:12', '2005-08-08 17:01:02'),
      ('6', '2005-08-09 07:03:44', '2005-08-09 17:00:00'),
      ('6', '2005-08-10 06:54:19', '2005-08-10 17:03:31'),
      ('6', '2005-08-11 07:00:05', '2005-08-11 17:02:57'),
      ('6', '2005-08-12 07:02:07', '2005-08-12 16:58:23');
    SELECT
      `Employees`.`First_Name`,
      `Employees`.`Last_Name`,
      `Hours`.`Clock_In`,
      `Hours`.`Clock_Out`
    FROM `Employees`
    INNER JOIN `Hours` ON `Employees`.`ID` = `Hours`.`ID`
    WHERE `Employees`.`First_Name` = 'Helmholtz'
    AND DATE_FORMAT(`Hours`.`Clock_In`, '%Y-%m-%d') >= '2005-08-08'
    AND DATE_FORMAT(`Hours`.`Clock_In`, '%Y-%m-%d') <= '2005-08-12'
    AND DATE_FORMAT(`Hours`.`Clock_In`, '%H:%i:%S') > '07:00:59';
    +------------+-----------+---------------------+---------------------+
    | First_Name | Last_Name | Clock_In            | Clock_Out           |
    +------------+-----------+---------------------+---------------------+
    | Helmholtz  | Watson    | 2005-08-09 07:03:44 | 2005-08-09 17:00:00 |
    | Helmholtz  | Watson    | 2005-08-12 07:02:07 | 2005-08-12 16:58:23 |
    +------------+-----------+---------------------+---------------------+
    SELECT
      `Employees`.`First_Name`,
      `Employees`.`Last_Name`,
      `Hours`.`Clock_In`,
      `Hours`.`Clock_Out`,
      (601 - TIMESTAMPDIFF(MINUTE, `Hours`.`Clock_In`, `Hours`.`Clock_Out`)) AS Difference -- Corrected Difference Calculation
    FROM `Employees`
    INNER JOIN `Hours` USING (`ID`) -- Simplified JOIN condition
    WHERE DATE_FORMAT(`Hours`.`Clock_In`, '%Y-%m-%d') BETWEEN '2005-08-08' AND '2005-08-12'
      AND TIME(`Hours`.`Clock_In`) > '07:00:59'
      AND TIMESTAMPDIFF(MINUTE, `Hours`.`Clock_In`, `Hours`.`Clock_Out`) < 601;
    +------------+-----------+---------------------+---------------------+------------+
    | First_Name | Last_Name | Clock_In            | Clock_Out           | Difference |
    +------------+-----------+---------------------+---------------------+------------+
    | Mustapha   | Mond      | 2005-08-12 07:02:29 | 2005-08-12 16:59:12 |          4 |
    ... (other rows matching the criteria)
    +------------+-----------+---------------------+---------------------+------------+
    CREATE SQL SECURITY INVOKER VIEW Employee_Tardiness AS
    SELECT
      `Employees`.`First_Name`,
      `Employees`.`Last_Name`,
      `Hours`.`Clock_In`,
      `Hours`.`Clock_Out`,
      (601 - TIMESTAMPDIFF(MINUTE, `Hours`.`Clock_In`, `Hours`.`Clock_Out`)) AS Difference
    FROM `Employees`
    INNER JOIN `Hours` USING (`ID`)
    WHERE DATE_FORMAT(`Hours`.`Clock_In`, '%Y-%m-%d') BETWEEN '2005-08-08' AND '2005-08-12'
      AND TIME(`Hours`.`Clock_In`) > '07:00:59'
      AND TIMESTAMPDIFF(MINUTE, `Hours`.`Clock_In`, `Hours`.`Clock_Out`) < 601;
    SELECT * FROM Employee_Tardiness;
    SELECT * FROM Employee_Tardiness WHERE Difference >= 5;
    +------------+-----------+---------------------+---------------------+------------+
    | First_Name | Last_Name | Clock_In            | Clock_Out           | Difference |
    +------------+-----------+---------------------+---------------------+------------+
    | Mustapha   | Mond      | 2005-08-12 07:02:29 | 2005-08-12 16:59:12 |          5 |
    ... (other rows where Difference >= 5)
    +------------+-----------+---------------------+---------------------+------------+
    CREATE USER 'mariabackup'@'localhost' IDENTIFIED BY 'mbu_passwd';
    GRANT RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR
          ON * TO 'mariabackup'@'localhost';
    mariadb-dump db_name > backup-file.sql
    mariadb db_name < backup-file.sql
    mariadb-hotcopy db_name [/path/to/new_directory]
    mariadb-hotcopy db_name_1 ... db_name_n /path/to/new_directory
    SELECT plugin_name, plugin_library, @@plugin_dir FROM information_schema.plugins WHERE plugin_type='ENCRYPTION';
    +---------------------+------------------------+---------------------------------------+
    | plugin_name         | plugin_library         | @@plugin_dir                          |
    +---------------------+------------------------+---------------------------------------+
    | file_key_management | file_key_management.so | /opt/homebrew/opt/mariadb/lib/plugin/ |
    +---------------------+------------------------+---------------------------------------+
    SHOW VARIABLES LIKE 'file_key_management%';                                                                 +------------------------------------------+------------------------------------------------+
    | Variable_name                            | Value                                          |
    +------------------------------------------+------------------------------------------------+
    | file_key_management_digest               | sha1                                           |
    | file_key_management_encryption_algorithm | aes_ctr                                        |
    | file_key_management_filekey              |                                                |
    | file_key_management_filename             | /opt/homebrew/etc/mysql/encryption/keyfile.txt |
    | file_key_management_use_pbkdf2           | 0                                              |
    +------------------------------------------+------------------------------------------------+
    mariadb-backup --backup --stream=xbstream | \ openssl enc -aes-256-cbc -k $BACKUP_PASSWORD > full_secure_backup.xb.enc
    BACKUP STAGE END;
    ERROR 2002 (HY000): Can't connect to MySQL server on 'myhost' (115)
    mariadbd --help --verbose
    #skip-networking
    skip-networking=0
    ./sql/mariadbd --print-defaults  # Adjust path to mariadbd if necessary
    GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.100.%'
      IDENTIFIED BY 'my-very-strong-password' WITH GRANT OPTION;
    FLUSH PRIVILEGES;
    [mysqld]
    ...
    #skip-networking
    #bind-address = 127.0.0.1
    ...
    [mysqld]
    bind-address = 0.0.0.0
    DESCRIBE clients;
    +-------------+-------------+------+-----+---------+-------+
    | Field       | Type        | Null | Key | Default | Extra |
    +-------------+-------------+------+-----+---------+-------+
    | cust_id     | int(11)     |      | PRI | 0       |       |
    | name        | varchar(25) | YES  |     | NULL    |       |
    | address     | varchar(25) | YES  |     | NULL    |       |
    | city        | varchar(25) | YES  |     | NULL    |       |
    | state       | char(2)     | YES  |     | NULL    |       |
    | zip         | varchar(10) | YES  |     | NULL    |       |
    | client_type | varchar(4)  | YES  |     | NULL    |       |
    +-------------+-------------+------+-----+---------+-------+
    mariadb-dump --user='your_username' --password='your_password' --add-locks db1 clients > clients.sql
    mariadb --user='your_username' --password='your_password' db1 < clients.sql
    ALTER TABLE clients
    ADD COLUMN status CHAR(2);
    ALTER TABLE clients
    ADD COLUMN address2 VARCHAR(25) AFTER address;
    ALTER TABLE clients
    ADD COLUMN new_first_column VARCHAR(50) FIRST;
    DESCRIBE clients;
    +-------------+-------------+------+-----+---------+-------+
    | Field       | Type        | Null | Key | Default | Extra |
    +-------------+-------------+------+-----+---------+-------+
    | cust_id     | int(11)     |      | PRI | 0       |       |
    | name        | varchar(25) | YES  |     | NULL    |       |
    | address     | varchar(25) | YES  |     | NULL    |       |
    | address2    | varchar(25) | YES  |     | NULL    |       |
    | city        | varchar(25) | YES  |     | NULL    |       |
    | state       | char(2)     | YES  |     | NULL    |       |
    | zip         | varchar(10) | YES  |     | NULL    |       |
    | client_type | varchar(4)  | YES  |     | NULL    |       |
    | status      | char(2)     | YES  |     | NULL    |       |
    +-------------+-------------+------+-----+---------+-------+
    ALTER TABLE clients
    CHANGE status status ENUM('AC','IA');
    ALTER TABLE clients
    CHANGE status active ENUM('AC','IA');
    ALTER TABLE clients
    MODIFY address1 VARCHAR(40); -- Assuming 'address1' is an existing column
    ALTER TABLE clients
        CHANGE address address1 VARCHAR(40),
        MODIFY active ENUM('yes','no','AC','IA'); -- Temporarily include all
    UPDATE clients
    SET active = 'yes'
    WHERE active = 'AC';
    
    UPDATE clients
    SET active = 'no'
    WHERE active = 'IA';
    ALTER TABLE clients
    MODIFY active ENUM('yes','no');
    ALTER TABLE clients
    DROP COLUMN client_type;
    ALTER TABLE clients
    ALTER state SET DEFAULT 'LA';
    ALTER TABLE clients
    ALTER state DROP DEFAULT;
    SHOW INDEX FROM clients\G
    *************************** 1. row ***************************
               Table: clients
          Non_unique: 0
            Key_name: PRIMARY
        Seq_in_index: 1
         Column_name: cust_id
           Collation: A
         Cardinality: 0
            Sub_part: NULL
              Packed: NULL
             Comment:
    ALTER TABLE clients
        DROP PRIMARY KEY,
        CHANGE cust_id client_id INT PRIMARY KEY;
    ALTER TABLE clients
        DROP INDEX cust_id_unique_idx, -- Use the actual Key_name
        CHANGE cust_id client_id INT UNIQUE;
    ALTER TABLE clients
        DROP INDEX cust_id, -- If cust_id is the Key_name
        CHANGE cust_id client_id INT UNIQUE;
    ALTER IGNORE TABLE clients
        DROP INDEX cust_id_idx, -- Assuming cust_id_idx is the name of the old INDEX
        CHANGE cust_id client_id INT UNIQUE;
    RENAME TABLE clients TO client_addresses;
    RENAME TABLE client_addresses TO db2.client_addresses;
    ALTER TABLE client_addresses
    ORDER BY city, name;
    author_id, publisher_id: INT, for storing numeric IDs.
  • year_pub: CHAR(4), a fixed-width string for the publication year.

  • description: TEXT, for longer descriptive text (up to 65,535 bytes).

  • and press [Enter].
  • SQL reserved words (e.g., CREATE, SELECT) are often written in uppercase for readability but are case-insensitive in MariaDB.

  • Database and table names are case-sensitive on Linux systems (as they map to directories and files) but generally not on Windows. Column names are case-insensitive.

  • Using lowercase for table and column names is a common convention.

  • mariadb -p
    CREATE DATABASE bookstore;
    USE bookstore;
    CREATE TABLE books (
        isbn CHAR(20) PRIMARY KEY,
        title VARCHAR(50),
        author_id INT,
        publisher_id INT,
        year_pub CHAR(4),
        description TEXT
    );
    DESCRIBE books;
    +--------------+-------------+------+-----+---------+-------+
    | Field        | Type        | Null | Key | Default | Extra |
    +--------------+-------------+------+-----+---------+-------+
    | isbn         | char(20)    | NO   | PRI | NULL    |       |
    | title        | varchar(50) | YES  |     | NULL    |       |
    | author_id    | int(11)     | YES  |     | NULL    |       |
    | publisher_id | int(11)     | YES  |     | NULL    |       |
    | year_pub     | char(4)     | YES  |     | NULL    |       |
    | description  | text        | YES  |     | NULL    |       |
    +--------------+-------------+------+-----+---------+-------+
    CREATE TABLE authors (
        author_id INT AUTO_INCREMENT PRIMARY KEY,
        name_last VARCHAR(50),
        name_first VARCHAR(50),
        country VARCHAR(50)
    );
    INSERT INTO authors (name_last, name_first, country)
    VALUES('Kafka', 'Franz', 'Czech Republic');
    INSERT INTO books (title, author_id, isbn, year_pub)
    VALUES('The Castle', '1', '0805211063', '1998');
    INSERT INTO books (title, author_id, isbn, year_pub)
    VALUES('The Trial', '1', '0805210407', '1995'),
          ('The Metamorphosis', '1', '0553213695', '1995'),
          ('America', '1', '0805210644', '1995');
    SELECT title FROM books;
    SELECT title FROM books LIMIT 5;
    SELECT title, name_last
    FROM books
    JOIN authors USING (author_id);
    SELECT title AS 'Kafka Books'
    FROM books
    JOIN authors USING (author_id)
    WHERE name_last = 'Kafka';
    +-------------------+
    | Kafka Books       |
    +-------------------+
    | The Castle        |
    | The Trial         |
    | The Metamorphosis |
    | America           |
    +-------------------+
    UPDATE books
    SET title = 'Amerika'
    WHERE isbn = '0805210644';
    DELETE FROM books
    WHERE author_id = '2034'; -- Assuming '2034' is the author_id to be deleted

    WEBINAR

    MariaDB 101: Learning the Basics of MariaDB

    Watch Now

    Creating a Database Structure

    SQL Syntax Notes

    Entering Data

    Retrieving Data

    Changing & Deleting Data

    ALTER TABLE documentation
    DROP TABLE documentation
    INSERT documentation
    AUTO_INCREMENT documentation
    LIMIT documentation
    JOIN documentation
    UPDATE documentation
    DELETE documentation
    tables are prefixed in the log with
    TEMPORARY
    . These drops are only logged when running
    or
    replication.
  • One DROP TABLE statement can be logged with up to 3 different DROP statements:

    • DROP TEMPORARY TABLE list_of_non_transactional_temporary_tables

    • DROP TEMPORARY TABLE list_of_transactional_temporary_tables

    • DROP TABLE list_of_normal_tables

  • The #sql-ib tables will be deleted automatically.
    DROP TABLE
    , some storage engines that were using multiple storage files, like
    , could have only a part of its internal files dropped. In
    , DROP TABLE was extended to be able to delete a table that was only partly dropped (
    ) as explained above. Atomic DROP TABLE is the final piece to make DROP TABLE fully reliable. Dropping multiple tables is crash-safe. See
    for more information.

    Variable slave-ddl-exec-mode.

    DROP TABLE `#mysql50##sql-...`;
    SELECT CONCAT('DROP TABLE IF EXISTS `', TABLE_SCHEMA, '`.`', TABLE_NAME, '`;')
    FROM information_schema.TABLES
    WHERE TABLE_SCHEMA = 'mydb';
    DROP TABLE Employees, Customers;

    WAIT/NOWAIT

    DROP TABLE in replication

    Dropping an Internal #sql-... Table

    Dropping All Tables in a Database

    Atomic DROP TABLE

    Examples

    Notes

    See Also

    SHOW WARNINGS
    foreign key
    binary log
    Identifier Qualifiers
    DROP privilege
    WAIT and NOWAIT
    replication
    binary log
    slave-ddl-exec-mode
    DROP TABLE is atomic.
    mariadbd process
    ALTER TABLE
    DROP DATABASE
    TABLES
    information_schema
    MDEV-25180
    binary log
    MDEV-11412
    Atomic DDL
    sequences
    mariadb-dump
    CREATE TABLE
    ALTER TABLE
    SHOW CREATE TABLE
    DROP SEQUENCE
    fill_help_tables.sql
    spinner
    statement
    mixed mode
    MyISAM
    MDEV-11412
    Atomic DDL

    .MRG files can be copied even while server is running as the file only contains a list of tables that are part of merge.

    - Compressing the Aria data file for easier distribution
  • mariadb-dump - Copying tables to other SQL servers. You can use the --tab to create a CSV file of your table content.

  • Archive

    Aria

    Requires clean shutdown. Table will automatically be fixed on the receiving server if aria_chk --zerofill was not run. If aria_chk --zerofill is run, then the table is immediately usable without any delays

    CSV

    CREATE TABLE new_table ... ENGINE=ARIA TRANSACTIONAL=0;
    ALTER TABLE new_table DISABLE_KEYS;
    # Fill the table with data:
    INSERT INTO new_table SELECT * ...
    FLUSH TABLE new_table WITH READ LOCK;
    
    # Copy table data to some external location, like /tmp with something
    # like cp /my/data/test/new_table.* /tmp/
    
    UNLOCK TABLES;
    > ls -l /tmp/new_table.*
    -rw-rw---- 1 mysql my 42396148 Sep 21 17:58 /tmp/new_table.MAD
    -rw-rw---- 1 mysql my     8192 Sep 21 17:58 /tmp/new_table.MAI
    -rw-rw---- 1 mysql my     1039 Sep 21 17:58 /tmp/new_table.frm
    > aria_pack /tmp/new_table
    Compressing /tmp/new_table.MAD: (922666 records)
    - Calculating statistics
    - Compressing file
    46.07%
    > aria_chk -rq --ignore-control-file --sort_buffer_size=1G /tmp/new_table
    Recreating table '/tmp/new_table'
    - check record delete-chain
    - recovering (with sort) Aria-table '/tmp/new_table'
    Data records: 922666
    - Fixing index 1
    State updated
    > ls -l /tmp/new_table.*
    -rw-rw---- 1 mysql my 26271608 Sep 21 17:58 /tmp/new_table.MAD
    -rw-rw---- 1 mysql my 10207232 Sep 21 17:58 /tmp/new_table.MAI
    -rw-rw---- 1 mysql my     1039 Sep 21 17:58 /tmp/new_table.frm

    Copying Tables When the MariaDB Server is Down

    Copying Tables Live From a Running MariaDB Server

    An Efficient Way to Give Someone Else Access to a Read Only Table

    Copying InnoDB's Transportable Tablespaces

    Importing Tables

    See Also

    FLUSH TABLES table_name FOR EXPORT
    UNLOCK TABLES
    myisamchk
    Copying Transportable Tablespaces
    datadir
    InnoDB
    ALTER TABLE ... IMPORT TABLESPACE
    Copying Transportable Tablespaces
    FLUSH TABLES FOR EXPORT
    FLUSH TABLES
    myisampack
    aria_pack
    spinner

    Big Data, Analytical

    ES 10.5+

    General Purpose

    Mixed Read/Write

    ES 10.5+

    Cache, Temp

    Temporary Data

    ES 10.5+

    Reads

    Reads

    ES 10.5+

    Write-Heavy

    I/O Reduction, SSD

    ES 10.5+

    Cloud

    Read-Only

    ES 10.5+

    Federation

    Sharding, Interlink

    ES 10.5+

    Aria

    Read-Heavy

    Reads

    ES 10.5+

    SHOW GLOBAL VARIABLES LIKE 'default_storage_engine';
    +------------------------+--------+
    | Variable_name          | Value  |
    +------------------------+--------+
    | default_storage_engine | InnoDB |
    +------------------------+--------+
    SHOW SESSION VARIABLES LIKE 'default_storage_engine';
    +------------------------+--------+
    | Variable_name          | Value  |
    +------------------------+--------+
    | default_storage_engine | InnoDB |
    +------------------------+--------+
    SET GLOBAL default_storage_engine='MyRocks';
    SET SESSION default_storage_engine='MyRocks';
    [mariadb]
    ...
    default_storage_engine=MyRocks
    SHOW ENGINES;
    CREATE TABLE accounts.messages (
      id INT PRIMARY KEY AUTO_INCREMENT,
      sender_id INT,
      receiver_id INT,
      message TEXT
    ) ENGINE = MyRocks;

    Examples

    Identify the Default Storage Engine

    Set the Default Storage Engine

    Configure the Default Storage Engine

    Identify Available Storage Engines

    Choose Storage Engine for a New Table

    Resources

    Engines for System Tables

    FAQ

    Can I use more than one storage engine on a server?

    Can I use more than one storage engine in a single query?

    What storage engine should I use for transactional or OLTP workloads?

    What storage engine should I use for analytical or OLAP workloads?

    What storage engine should I use if my application performs both transactional and analytical queries?

    Reference

    MariaDB Server Reference

    SHOW GLOBAL VARIABLES
    default_storage_engine
    SHOW SESSION VARIABLES
    Aria Storage Engine
    MyISAM Storage Engine
    CREATE TABLE
    InnoDB
    hybrid transactional-analytical processing (HTAP)
    InnoDB
    Plugins
    Information Schema ENGINES table
    Information Schema TABLES table
    spinner

    Analytics, HTAP

    An Aria table's default value for the TRANSACTIONAL table option depends on the table's value for the ROW_FORMAT table option. See below for more details.
  • If the TRANSACTIONAL table option is set for an Aria table, the table does not actually support transactions. See MDEV-21364 for more information. In this context, transactional just means crash-safe.

  • If TRANSACTIONAL is not set to any value, then any row format is supported. If ROW_FORMAT is set, then the table will use that row format. Otherwise, the table will use the default PAGE row format. In this case, if the table uses the PAGE row format, then it are crash-safe. If it uses some other row format, then it will not be crash-safe.

    At startup Aria will check the Aria logs and automatically recover the tables from the last checkpoint if the server was not taken down correctly. See Aria Log Files

    The default value 8192, should be ok for most cases. The only problem with a higher value is that it takes longer to find a packed key in the block as one has to search roughly 8192/2 to find each key. We plan to fix this by adding a dictionary at the end of the page to be able to do a binary search within the block before starting a scan. Until this is done and key lookups takes too long time even if you are not hitting disk, then you should consider making this smaller.
  • Possible values to try are 2048, 4096 or 8192

  • Note that you can't change this without dumping, deleting old tables and deleting all log files and then restoring your Aria tables. (This is the only option that requires a dump and load.)

  • aria-log-purge-type

    • Set this to "at_flush" if you want to keep a copy of the transaction logs (good as an extra backup). The logs will stay around until you execute FLUSH ENGINE LOGS.

  • trid is the highest transaction number seen so far. Used by recovery.
    Aria file version: 1
    Block size: 8192
    maria_uuid: ee948482-6cb7-11ed-accb-3c7c3ff16468
    last_checkpoint_lsn: (1,0x235a)
    last_log_number: 1
    trid: 28
    recovery_failures: 0

    Startup Options for Aria

    Aria Log Files

    Missing valid id

    See Also

    row format
    CHECKSUM TABLE
    row format
    ALTER TABLE
    Aria System Variables
    aria-pagecache-buffer-size
    aria-block-size
    When is it safe to remove old log files
    Aria FAQ
    spinner

    Delimiter: Use a character not commonly found in your data to separate fields. The pipe symbol (|) is often a good choice. Tab (\t) is also common.

  • Record Separator: Use line feeds (\n) to separate records.

  • Align Columns (Recommended for Simplicity): Ideally, the order and number of columns in your text file should match the target MariaDB table.

    • If the table has extra columns not in your file, they will be filled with their default values (or NULL).

    • If your file has extra columns not in the table, you'll need to specify which file columns to load (see "Mapping File Columns to Table Columns" below) or remove them from the text file.

  • Clean Data: Remove any header rows or footer information from the text file unless you plan to skip them during import (see IGNORE N LINES below).

  • Upload File: Transfer the text file to a location accessible by the MariaDB server.

    • Use ASCII mode for FTP transfers to ensure correct line endings.

    • For security, upload data files to non-public directories on the server.

  • The LOAD DATA INFILE statement is a powerful SQL command for importing data from text files. Ensure the MariaDB user has the FILE privilege.

    Basic Syntax:

    First, connect to MariaDB using the mariadb client and select your target database:

    Then, load the data:

    • Replace /tmp/prospects.txt with the actual path to your data file on the server. On Windows, paths use forward slashes (e.g., 'C:/tmp/prospects.txt').

    • prospect_contact is the target table. You can also specify database_name.table_name.

    • FIELDS TERMINATED BY '|' specifies the field delimiter. For tab-delimited, use '\t'.

    • The default record delimiter is the line feed (\n).

    Specifying Line Terminators and Enclosing Characters:

    If your file has custom line endings or fields enclosed by characters (e.g., quotes):

    • ENCLOSED BY '"': Specifies that fields are enclosed in double quotes.

    • LINES STARTING BY '"': Indicates each line starts with a double quote.

    • TERMINATED BY '"\r\n': Indicates each line ends with a double quote followed by a Windows-style carriage return and line feed.

    • To specify a single quote as an enclosing character, you can escape it or put it within double quotes: ENCLOSED BY '\'' or ENCLOSED BY "'".

    When importing data, you might encounter records with primary key values that already exist in the target table.

    • Default Behavior: MariaDB attempts to import all rows. If duplicates are found and the table has a primary or unique key that would be violated, an error occurs, and subsequent rows may not be imported.

    • REPLACE: If you want new data from the file to overwrite existing rows with the same primary key:SQL

      LOAD DATA INFILE '/tmp/prospects.txt'
      REPLACE INTO TABLE prospect_contact
      FIELDS TERMINATED BY '|';
    • IGNORE: If you want to keep existing rows and skip importing duplicate records from the file:SQL

    If the target table is actively being used, importing data can lock it, preventing access.

    • LOW_PRIORITY: To allow other users to read from the table while the load operation is pending, use LOW_PRIORITY. The load will wait until no other clients are reading the table.SQL

      LOAD DATA LOW_PRIORITY INFILE '/tmp/prospects.txt'
      INTO TABLE prospect_contact
      FIELDS TERMINATED BY '|';

      Without LOW_PRIORITY or CONCURRENT, the table is typically locked for the duration of the import.

    Binary Line Endings:

    If your file has Windows CRLF line endings and was uploaded in binary mode, you can specify the hexadecimal value:

    Note: No quotes around the hexadecimal value.

    Skipping Header Lines:

    To ignore a certain number of lines at the beginning of the file (e.g., a header row):

    SQL

    Handling Escaped Characters:

    If fields are enclosed by quotes and contain embedded quotes that are escaped by a special character (e.g., # instead of the default backslash \):

    Mapping File Columns to Table Columns:

    If the order or number of columns in your text file differs from the target table, you can specify the column mapping at the end of the LOAD DATA INFILE statement.

    Assume prospect_contact table has: (row_id INT AUTO_INCREMENT, name_first VARCHAR, name_last VARCHAR, telephone VARCHAR).

    And prospects.txt has columns in order: Last Name, First Name, Telephone.

    • MariaDB will map data from the file's first column to name_last, second to name_first, and third to telephone.

    • The row_id column in the table, not being specified in the list, will be filled by its default mechanism (e.g., AUTO_INCREMENT or DEFAULT value, or NULL).

    The mariadb-import utility (known as mysqlimport before MariaDB 10.5) is a command-line program that acts as a wrapper for LOAD DATA INFILE. It's useful for scripting imports.

    Syntax:

    • This command is run from the system shell, not within the mariadb client.

    • Lines are continued with \ for readability here; it can be a single line.

    • --password: If the password value is omitted, you'll be prompted.

    • The database name (sales_dept) is specified before the file path.

    • File Naming: mariadb-import expects the text file's name (without extension) to match the target table name (e.g., prospect_contact.txt for table prospect_contact). If your file is prospects.txt and table is prospect_contact, you might need to rename the file or import into a temporary table named prospects first.

    • --verbose: Shows progress information.

    • You can list multiple text files to import into correspondingly named tables.

    Some web hosts disable LOAD DATA INFILE or mariadb-import for security reasons. A workaround involves using mariadb-dump:

    1. Prepare Data Locally: Prepare your delimited text file (e.g., prospects.txt).

    2. Local Import: If you have a local MariaDB server, import the text file into a local table (e.g., local_db.prospect_contact) using LOAD DATA INFILE as described above.

    3. Local Export with mariadb-dump: Export the data from your local table into an SQL file containing INSERT statements.

      • --no-create-info (or -t): Prevents the CREATE TABLE statement from being included, outputting only INSERT statements. This is useful if the table already exists on the remote server.

    4. Upload SQL File: Upload the generated .sql file (e.g., prospects.sql) to your web server (in ASCII mode).

    5. Remote Import of SQL File: Log into your remote server's shell and import the SQL file using the mariadb client:

    Handling Duplicates with mariadb-dump Output:

    mariadb-dump does not have a REPLACE flag like LOAD DATA INFILE. If the target table might contain duplicates:

    • Open the .sql file generated by mariadb-dump in a text editor.

    • Perform a search and replace operation to change all occurrences of INSERT INTO to REPLACE INTO. The syntax for INSERT and REPLACE (for the data values part) is similar enough that this often works. Test thoroughly.

    • Flexibility: MariaDB provides powerful and flexible options for data importing. Understanding the details of LOAD DATA INFILE and mariadb-import can save significant effort.

    • Data Validation: While these tools are efficient for bulk loading, they may not perform extensive data validation beyond basic type compatibility. Cleanse and validate your data as much as possible before importing.

    • Character Sets: Ensure your data file's character set is compatible with the target table's character set to avoid data corruption. You can specify character sets in LOAD DATA INFILE.

    • Other Tools/Methods: For very complex transformations or ETL (Extract, Transform, Load) processes, dedicated ETL tools or scripting languages (e.g., Python, Perl with database modules) might be more suitable, though they are beyond the scope of this guide.

    This page is licensed: CC BY-SA / Gnu FDL

    Preparing Your Data File

    USE sales_dept; -- Or your database name
    LOAD DATA INFILE '/tmp/prospects.txt'
    INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|';
    LOAD DATA INFILE '/tmp/prospects.txt'
    INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|' ENCLOSED BY '"'
    LINES STARTING BY '"' TERMINATED BY '"\r\n';
    LOAD DATA INFILE '/tmp/prospects.txt'
    INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|'
    LINES TERMINATED BY 0x0d0a; -- 0x0d is carriage return, 0x0a is line feed
    LOAD DATA INFILE '/tmp/prospects.txt'
    INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|'
    IGNORE 1 LINES; -- Skips the first line
    LOAD DATA INFILE '/tmp/prospects.txt'
    INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|'
        ENCLOSED BY '"'
        ESCAPED BY '#'
    IGNORE 1 LINES;
    LOAD DATA INFILE '/tmp/prospects.txt'
    INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|' -- Or your actual delimiter, e.g., 0x09 for tab
    ENCLOSED BY '"'
    ESCAPED BY '#'
    IGNORE 1 LINES
    (name_last, name_first, telephone);
    mariadb-import --user='your_username' --password='your_password' \
        --fields-terminated-by='|' --lines-terminated-by='\r\n' \
        --replace --low-priority --fields-enclosed-by='"' \
        --fields-escaped-by='#' --ignore-lines='1' --verbose \
        --columns='name_last,name_first,telephone' \
        sales_dept '/tmp/prospect_contact.txt'

    Using LOAD DATA INFILE

    Handling Duplicate Rows

    Importing into Live Tables

    Advanced LOAD DATA INFILE Options

    Using the mariadb-import Utility

    Dealing with Web Hosting Restraints

    Key Considerations

    spinner
    Unique and not NULL.
  • Unique Indexes: Must be unique but can contain NULL values.

  • Plain Indexes (or Regular Indexes): Not necessarily unique.

  • Full-Text Indexes: Used for full-text searching capabilities.

  • A primary key uniquely identifies each record in a table. Its values must be unique, and it cannot contain NULL values. Each table can have only one primary key.

    InnoDB Considerations:

    • In InnoDB tables, the primary key is included as a suffix in all other indexes. Therefore, keeping the primary key compact (e.g., using an appropriate integer type) is important for performance and storage efficiency.

    • If a table has no explicitly defined primary key and no UNIQUE indexes, InnoDB automatically creates an invisible 6-byte clustered index.

    Using AUTO_INCREMENT: The AUTO_INCREMENT attribute is commonly used with numeric primary keys to automatically generate a unique ID for each new row.

    Note: The column defined as a primary key (or part of it) must be explicitly declared as NOT NULL.

    Adding a Primary Key to an Existing Table: Use ALTER TABLE. You cannot create a primary key with CREATE INDEX.

    Finding Tables Without Primary Keys: This query uses the information_schema database to find tables lacking primary keys:

    A unique index ensures that all values in the indexed column (or combination of columns) are unique. However, unlike a primary key, columns in a unique index can store NULL values.

    Each key value uniquely identifies a row, but not every row needs to be represented if NULLs are allowed.

    Behavior (MariaDB 10.5+):

    • If the index type is not specified, UNIQUE typically creates a BTREE index, usable by the optimizer.

    • If a key exceeds the maximum length for the storage engine and the engine supports long unique indexes, a HASH key might be created to enforce uniqueness.

    Creating Unique Indexes: During table creation:

    After table creation using ALTER TABLE:

    After table creation using CREATE UNIQUE INDEX:

    Multi-Column Unique Indexes: An index can span multiple columns. MariaDB can use the leftmost part(s) of such an index if it cannot use the whole index (except for HASH indexes).

    NULL Values in Unique Indexes: A UNIQUE constraint allows multiple NULL values because in SQL, NULL is never equal to another NULL.

    Verification:

    Conditional Uniqueness with Virtual Columns: You can enforce uniqueness over a subset of rows using unique indexes on virtual columns. This example ensures user_name is unique for 'Active' or 'On-Hold' users, but allows duplicate names for 'Deleted' users:

    Trailing Pad Characters: If a unique index is on a column where trailing pad characters are stripped or ignored (e.g., CHAR vs VARCHAR behavior), inserts where values differ only by the number of trailing pad characters can result in duplicate-key errors.

    Long Keys and HASH Indexes (MariaDB 10.4+): For engines like InnoDB, UNIQUE can be used with various column types and numbers. If a key's length exceeds the engine's maximum, a HASH key may be created.

    Example output snippet showing USING HASH:

    Plain indexes do not enforce uniqueness; they are primarily used to speed up data retrieval.

    Full-text indexes are used for performing full-text searches on text data. For details, see the Full-Text Indexes documentation.

    • Index for Queries: Add indexes that match the WHERE clauses, JOIN conditions, and ORDER BY clauses of your application's queries.

    • Avoid Over-Indexing: Extra indexes consume storage and can slow down INSERT, UPDATE, and DELETE operations.

    • Impact of Table Size: Indexes provide more significant speed-ups on large tables (larger than buffer sizes) than on very small tables.

    • Use EXPLAIN: Analyze your queries with the statement to determine if indexes are being used effectively and identify columns that might benefit from indexing.

    • LIKE '%word%': Queries using a leading wildcard in a LIKE clause (e.g., LIKE '%word%') typically cannot use standard BTREE indexes effectively and may result in full table scans unless a full-text index is used.

    • Delayed Writes: For tables with many reads and writes, consider storage engine options or server configurations related to delayed writes to potentially improve performance by batching disk I/O. (This is an advanced topic.)

    • Creating Indexes on Existing Tables: Use CREATE INDEX index_name ON table_name (column_list);

    • Large Tables: For very large tables, it's often faster to load data into the table first and then create indexes, rather than creating indexes on an empty table and then loading data.

    • SHOW INDEX FROM table_name;: Displays information about all indexes on a table.

      SHOW INDEX FROM Employees;
    • SHOW CREATE TABLE table_name;: Shows the CREATE TABLE statement, which includes definitions for all indexes.SQL

      SHOW CREATE TABLE Employees\G

    Remove an index if:

    • It is rarely or never used. Unused indexes still incur overhead during data modification operations.

    • Identifying Unused Indexes:

      • If user statistics are enabled, query the information_schema.INDEX_STATISTICS table.

      • If the is enabled and the log_queries_not_using_indexes is ON, queries performing full table scans will be logged, which can indicate missing or ineffective indexes.

    This page is licensed: CC BY-SA / Gnu FDL

    Index Types Overview

    The Essentials of an Index
    CREATE TABLE `Employees` (
      `ID` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
      `First_Name` VARCHAR(25) NOT NULL,
      `Last_Name` VARCHAR(25) NOT NULL,
      `Position` VARCHAR(25) NOT NULL,
      PRIMARY KEY (`ID`)
    );
    ALTER TABLE Employees ADD PRIMARY KEY(ID);
    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 NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')
      AND c.CONSTRAINT_NAME IS NULL;
    CREATE TABLE `Employees` (
      `ID` TINYINT(3) UNSIGNED NOT NULL,
      `Employee_Code` VARCHAR(25) NOT NULL,
      `First_Name` VARCHAR(25) NOT NULL,
      PRIMARY KEY (`ID`),
      UNIQUE KEY `UK_EmpCode` (`Employee_Code`) -- Naming the unique key is good practice
    );
    ALTER TABLE Employees ADD UNIQUE `UK_HomePhone` (`Home_Phone`);
    CREATE UNIQUE INDEX `IX_Position` ON Employees(Position);
    CREATE TABLE t1 (a INT NOT NULL, b INT, UNIQUE (a,b));
    INSERT INTO t1 VALUES (1,1), (2,2);
    INSERT INTO t1 VALUES (2,1); -- Valid: (2,1) is unique, though '2' in 'a' and '1' in 'b' are not individually unique here.
    SELECT * FROM t1;
    +---+------+
    | a | b    |
    +---+------+
    | 1 |    1 |
    | 2 |    1 |
    | 2 |    2 |
    +---+------+
    INSERT INTO t1 VALUES (3,NULL), (3, NULL); -- Both rows are inserted
    SELECT * FROM t1;
    +---+------+
    | a | b    |
    +---+------+
    | 1 |    1 |
    | 2 |    1 |
    | 2 |    2 |
    | 3 | NULL |
    | 3 | NULL |
    +---+------+
    SELECT (3, NULL) = (3, NULL);
    +-----------------------+
    | (3, NULL) = (3, NULL) |
    +-----------------------+
    |                     0 | -- 0 means false
    +-----------------------+
    CREATE TABLE Table_1 (
      user_name VARCHAR(10),
      status ENUM('Active', 'On-Hold', 'Deleted'),
      del CHAR(0) AS (IF(status IN ('Active', 'On-Hold'), '', NULL)) PERSISTENT,
      UNIQUE(user_name, del)
    );
    -- Example table definition (simplified for brevity)
    CREATE TABLE t_long_keys (
      a INT PRIMARY KEY,
      b BLOB,
      c1 VARCHAR(1000),
      UNIQUE KEY `uk_b` (b),
      UNIQUE KEY `uk_c1` (c1)
    ) ENGINE=InnoDB;
    
    -- SHOW CREATE TABLE might reveal 'USING HASH' for uk_b or uk_c1 if they exceed length limits
    SHOW CREATE TABLE t_long_keys\G
    ...
      UNIQUE KEY `uk_b` (`b`) USING HASH,
    ...
    CREATE TABLE t2 (a INT NOT NULL, b INT, INDEX `idx_a_b` (a,b));
    INSERT INTO t2 VALUES (1,1), (2,2), (2,2); -- Duplicate (2,2) is allowed
    SELECT * FROM t2;
    +---+------+
    | a | b    |
    +---+------+
    | 1 |    1 |
    | 2 |    2 |
    | 2 |    2 |
    +---+------+

    Primary Key

    Unique Index

    Plain Indexes (Regular Indexes)

    Full-Text Indexes

    Choosing Indexes

    Viewing Indexes

    When to Remove an Index

    spinner
    here if you want to use a different user name. This is the MariaDB user name, not the Linux user name. The password for the MariaDB user
    root
    will probably be different from the Linux user
    root
    . Incidentally, it's not a good security practice to use the
    root
    user unless you have a specific administrative task to perform for which only
    root
    has the needed privileges.

    The -p option above instructs the mariadb client to prompt you for the password. If the password for the root user hasn't been set yet, then the password is blank and you would just hit [Enter] when prompted. The -h option is for specifying the host name or the IP address of the server. This would be necessary if the client is running on a different machine than the server. If you've secure-shelled into the server machine, you probably won't need to use the host option. In fact, if you're logged into Linux as root, you won't need the user option—the -p is all you'll need. Once you've entered the line above along with the password when prompted, you are logged into MariaDB through the client. To exit, type quit or exit and press [Enter].

    In order to be able to add and to manipulate data, you first have to create a database structure. Creating a database is simple. You would enter something like the following from within the mariadb client:

    This very minimal, first SQL statement will create a sub-directory called bookstore on the Linux filesystem in the directory which holds your MariaDB data files. It won't create any data, obviously. It'll just set up a place to add tables, which will in turn hold data. The second SQL statement above will set this new database as the default database. It will remain your default until you change it to a different one or until you log out of MariaDB.

    The next step is to begin creating tables. This is only a little more complicated. To create a simple table that will hold basic data on books, we could enter something like the following:

    This SQL statement creates the table books with six fields, or rather columns. The first column (isbn) is an identification number for each row—this name relates to the unique identifier used in the book publishing business. It has a fixed-width character type of 20 characters. It are the primary key column on which data are indexed. The column data type for the book title is a variable width character column of fifty characters at most. The third and fourth columns are used for identification numbers for the author and the publisher. They are integer data types. The fifth column is used for the publication year of each book. The last column is for entering a description of each book. It's a TEXT data type, which means that it's a variable width column and it can hold up to 65535 bytes of data for each row. There are several other data types that may be used for columns, but this gives you a good sampling.

    To see how the table we created looks, enter the following SQL statement:

    To change the settings of a table, you can use the ALTER TABLE statement. I'll cover that statement in another article. To delete a table completely (including its data), you can use the DROP TABLE statement, followed by the table name. Be careful with this statement since it's not reversible.

    The next table we'll create for our examples is the authors table to hold author information. This table will save us from having to enter the author's name and other related data for each book written by each author. It also helps to ensure consistency of data: there's less chance of inadvertent spelling deviations.

    We'll join this table to the books table as needed. For instance, we would use it when we want a list of books along with their corresponding authors' names. For a real bookstore's database, both of these tables would probably have more columns. There would also be several more tables. For the examples that follow, these two tables as they are enough.

    Before moving on to the next step of adding data to the tables, let me point out a few minor items that I've omitted mentioning. SQL statements end with a semi-colon (or a \G). You can spread an SQL statement over multiple lines. However, it won't be passed to the server by the client until you terminate it with a semi-colon and hit [Enter]. To cancel an SQL statement once you've started typing it, enter \c and press [Enter].

    As a basic convention, reserved words are printed in all capital letters. This isn't necessary, though. MariaDB is case-insensitive with regards to reserved words. Database and table names, however, are case-sensitive on Linux. This is because they reference the related directories and files on the filesystem. Column names aren't case sensitive since they're not affected by the filesystem, per se. As another convention, we use lower-case letters for structural names (e.g., table names). It's a matter of preference for deciding on names.

    The primary method for entering data into a table is to use the INSERT statement. As an example, let's enter some information about an author into the authors table. We'll do that like so:

    This will add the name and country of the author Franz Kafka to the authors table. We don't need to give a value for the author_id since that column was created with the AUTO_INCREMENT option. MariaDB will automatically assign an identification number. You can manually assign one, especially if you want to start the count at a higher number than 1 (e.g., 1000). Since we are not providing data for all of the columns in the table, we have to list the columns for which we are giving data and in the order that the data is given in the set following the VALUES keyword. This means that we could give the data in a different order.

    For an actual database, we would probably enter data for many authors. We'll assume that we've done that and move on to entering data for some books. Below is an entry for one of Kafka's books:

    This adds a record for Kafka's book, The Castle. Notice that we mixed up the order of the columns, but it still works because both sets agree. We indicate that the author is Kafka by giving a value of 1 for the author_id. This is the value that was assigned by MariaDB when we entered the row for Kafka earlier. Let's enter a few more books for Kafka, but by a different method:

    In this example, we've added three books in one statement. This allows us to give the list of column names once. We also give the keyword VALUES only once, followed by a separate set of values for each book, each contained in parentheses and separated by commas. This cuts down on typing and speeds up the process. Either method is fine and both have their advantages. To be able to continue with our examples, let's assume that data on thousands of books has been entered. With that behind us, let's look at how to retrieve data from tables.

    The primary method of retrieving data from tables is to use a SELECT statement. There are many options available with the SELECT statement, but you can start simply. As an example, let's retrieve a list of book titles from the books table:

    This will display all of the rows of books in the table. If the table has thousands of rows, MariaDB will display thousands. To limit the number of rows retrieved, we could add a LIMIT clause to the SELECT statement like so:

    This will limit the number of rows displayed to five. To be able to list the author's name for each book along with the title, you will have to join the books table with the authors table. To do this, we can use the JOIN clause like so:

    Notice that the primary table from which we're drawing data is given in the FROM clause. The table to which we're joining is given in the JOIN clause along with the commonly named column (i.e., author_id) that we're using for the join.

    To retrieve the titles of only books written by Kafka based on his name (not the author_id), we would use the WHERE clause with the SELECT statement. This would be entered like the following:

    This statement will list the titles of Kafka books stored in the database. Notice that I've added the AS parameter next to the column name title to change the column heading in the results set to Kafka Books. This is known as an alias. Looking at the results here, we can see that the title for one of Kafka's books is incorrect. His book Amerika is spelled above with a "c" in the table instead of a "k". This leads to the next section on changing data.

    In order to change existing data, a common method is to use the UPDATE statement. When changing data, though, we need to be sure that we change the correct rows. In our example, there could be another book with the title America written by a different author. Since the key column isbn has only unique numbers and we know the ISBN number for the book that we want to change, we can use it to specify the row.

    This will change the value of the title column for the row specified. We could change the value of other columns for the same row by giving the column = value for each, separated by commas.

    If we want to delete a row of data, we can use the DELETE statement. For instance, suppose that our fictitious bookstore has decided no longer to carry books by John Grisham. By first running a SELECT statement, we determine the identification number for the author to be 2034. Using this author identification number, we could enter the following:

    This statement will delete all rows from the table books for the author_id given. To do a clean job of it, we'll have to do the same for the authors table. We would just replace the table name in the statement above; everything else would be the same.

    This is a very basic primer for using MariaDB. Hopefully, it gives you the idea of how to get started with MariaDB. Each of the SQL statements mentioned here have several more options and clauses each. We will cover these statements and others in greater detail in other articles. For now, though, you can learn more about them from experimenting and by further reading of the documentation online documentation.

    This page is licensed: CC BY-SA / Gnu FDL

    mariadb -u root -p -h localhost

    Connecting to MariaDB

    WEBINAR

    MariaDB 101: Learning the Basics of MariaDB

    CREATE DATABASE bookstore;
    
    USE bookstore;
    CREATE TABLE books (
    isbn CHAR(20) PRIMARY KEY, 
    title VARCHAR(50),
    author_id INT,
    publisher_id INT,
    year_pub CHAR(4),
    description TEXT );
    DESCRIBE books;
    +--------------+-------------+------+-----+---------+-------+
    | Field        | Type        | Null | Key | Default | Extra |
    +--------------+-------------+------+-----+---------+-------+
    | isbn         | char(20)    | NO   | PRI | NULL    |       |
    | title        | varchar(50) | YES  |     | NULL    |       |
    | author_id    | int(11)     | YES  |     | NULL    |       |
    | publisher_id | int(11)     | YES  |     | NULL    |       |
    | year_pub     | char(4)     | YES  |     | NULL    |       |
    | description  | text        | YES  |     | NULL    |       |
    +--------------+-------------+------+-----+---------+-------+
    CREATE TABLE authors
    (author_id INT AUTO_INCREMENT PRIMARY KEY,
    name_last VARCHAR(50),
    name_first VARCHAR(50),
    country VARCHAR(50) );
    INSERT INTO authors
    (name_last, name_first, country)
    VALUES('Kafka', 'Franz', 'Czech Republic');
    INSERT INTO books
    (title, author_id, isbn, year_pub)
    VALUES('The Castle', '1', '0805211063', '1998');
    INSERT INTO books
    (title, author_id, isbn, year_pub)
    VALUES('The Trial', '1', '0805210407', '1995'),
    ('The Metamorphosis', '1', '0553213695', '1995'),
    ('America', '1', '0805210644', '1995');
    SELECT title 
    FROM books;
    SELECT title 
    FROM books
    LIMIT 5;
    SELECT title, name_last 
    FROM books 
    JOIN authors USING (author_id);
    SELECT title AS 'Kafka Books'
    FROM books 
    JOIN authors USING (author_id)
    WHERE name_last = 'Kafka';
    
    +-------------------+
    | Kafka Books       |
    +-------------------+
    | The Castle        |
    | The Trial         |
    | The Metamorphosis |
    | America           |
    +-------------------+
    UPDATE books
    SET title = 'Amerika'
    WHERE isbn = '0805210644';
    DELETE FROM books
    WHERE author_id = '2034';

    Creating a Structure

    Minor Items

    Entering Data

    Retrieving Data

    Changing & Deleting Data

    Conclusion

    stage. This file has 3 roles:
    1. In the source server, ib_logfile0 is the first (and possibly the only) InnoDB redo log file.

    2. In the non-prepared backup, ib_logfile0 contains all of the InnoDB redo log copied during the backup.

    3. During the --prepare stage, ib_logfile0 is initialized as an empty InnoDB redo log file. That way, if the backup is manually restored, any pre-existing InnoDB redo log files get overwritten by the empty one. This helps to prevent certain kinds of known issues.

    mariadb_backup_binlog_info

    This file stores the binary log file name and position that corresponds to the backup.

    This file also stores the value of the gtid_current_pos system variable that correspond to the backup, like this:

    mariadb-bin.000096 568 0-1-2

    The values in this file are only guaranteed to be consistent with the backup if the --no-lock option was not provided when the backup was taken.

    xtrabackup_binlog_info

    This file stores the binary log file name and position that corresponds to the backup.

    This file also stores the value of the system variable that correspond to the backup, like this:

    The values in this file are only guaranteed to be consistent with the backup if the option was not provided when the backup was taken.

    mariadb_backup_binlog_pos_innodb

    This file is created by mariadb-backup to provide the binary log file name and position when the --no-lock option is used. It can be used instead of the xtrabackup_binlog_info file to obtain transactionally consistent binlog coordinates from the backup of a master server with the --no-lock option to minimize the impact on a running server.

    Whenever a transaction is committed inside InnoDB when the binary log is enabled, the corresponding binlog coordinates are written to the InnoDB redo log along with the transaction commit. This allows one to restore the binlog coordinates corresponding to the last commit done by InnoDB along with a backup.

    The limitation of using xtrabackup_binlog_pos_innodb with the --no-lock option is that no DDL or modification of non-transactional tables should be done during the backup. If the last event in the binlog is a DDL/non-transactional update, the coordinates in the file xtrabackup_binlog_pos_innodb are too old. But as long as only InnoDB updates are done during the backup, the coordinates are correct.

    xtrabackup_binlog_pos_innodb

    This file is created by mariadb-backup to provide the binary log file name and position when the --no-lock option is used. It can be used instead of the xtrabackup_binlog_info file to obtain transactionally consistent binlog coordinates from the backup of a master server with the --no-lock option to minimize the impact on a running server.

    Whenever a transaction is committed inside InnoDB when the binary log is enabled, the corresponding binlog coordinates are written to the InnoDB redo log along with the transaction commit. This allows one to restore the binlog coordinates corresponding to the last commit done by InnoDB along with a backup.

    The limitation of using

    mariadb_backup_checkpoints

    The xtrabackup_checkpoints file contains metadata about the backup.

    For example:

    backup_type = full-backuped
    from_lsn = 0
    to_lsn = 1635102
    last_lsn = 1635102
    recover_binlog_info = 0

    See below for a description of the fields.

    If the --extra-lsndir option is provided, then an extra copy of this file are saved in that directory.

    xtrabackup_checkpoints

    The xtrabackup_checkpoints file contains metadata about the backup.

    For example:

    See below for a description of the fields.

    If the --extra-lsndir option is provided, then an extra copy of this file are saved in that directory.

    If the backup is a non-prepared full backup or a non-prepared partial backup, then backup_type is set to full-backuped.

    If the backup is a non-prepared incremental backup, then backup_type is set to incremental.

    If the backup has already been prepared, then backup_type is set to log-applied.

    If backup_type is full-backuped, then from_lsn has the value of 0.

    If backup_type is incremental, then from_lsn has the value of the log sequence number (LSN) at which the backup started reading from the InnoDB redo log. This is internally used by mariadb-backup when preparing incremental backups.

    This value can be manually set during an incremental backup with the --incremental-lsn option. However, it is generally better to let mariadb-backup figure out the from_lsn automatically by specifying a parent backup with the --incremental-basedir option.

    to_lsn has the value of the log sequence number (LSN) of the last checkpoint in the InnoDB redo log. This is internally used by mariadb-backup when preparing incremental backups.

    last_lsn has the value of the last log sequence number (LSN) read from the InnoDB redo log. This is internally used by mariadb-backup when preparing incremental backups.

    mariadb_backup_info

    Contains information about the backup. The fields in this file are listed below.

    If the --extra-lsndir option is provided, an extra copy of this file is saved in that directory.

    xtrabackup_info

    Contains information about the backup. The fields in this file are listed below.

    If the --extra-lsndir option is provided, an extra copy of this file is saved in that directory.

    If a UUID was provided by the --incremental-history-uuid option, then it are saved here. Otherwise, this is the empty string.

    If a name was provided by the --history or the ---incremental-history-name options, then it are saved here. Otherwise, this is the empty string.

    The name of the mariadb-backup executable that performed the backup. This is generally mariadb-backup.

    The arguments that were provided to mariadb-backup when it performed the backup.

    The version of mariadb-backup that performed the backup.

    The version of mariadb-backup that performed the backup.

    The version of MariaDB Server that was backed up.

    The time that the backup started.

    The time that the backup ended.

    The amount of time that mariadb-backup held its locks.

    This field stores the binary log file name and position that corresponds to the backup.

    This field also stores the value of the gtid_current_pos system variable that correspond to the backup.

    The values in this field are only guaranteed to be consistent with the backup if the --no-lock option was not provided when the backup was taken.

    This is identical to from_lsn in xtrabackup_checkpoints.

    If the backup is a full backup, then innodb_from_lsn has the value of 0.

    If the backup is an incremental backup, then innodb_from_lsn has the value of the log sequence number (LSN) at which the backup started reading from the InnoDB redo log.

    This is identical to to_lsn in xtrabackup_checkpoints.

    innodb_to_lsn has the value of the log sequence number (LSN) of the last checkpoint in the InnoDB redo log.

    If the backup is a partial backup, then this value are Y.

    Otherwise, this value are N.

    If the backup is an incremental backup, then this value are Y.

    Otherwise, this value are N.

    This field's value is the format of the backup.

    If the --stream option was set to xbstream, then this value are xbstream.

    If the --stream option was not provided, then this value are file.

    If the --compress option was provided, then this value are compressed.

    Otherwise, this value are N.

    mariadb_backup_slave_info

    If the --slave-info option is provided, this file contains the CHANGE MASTER command that can be used to set up a new server as a slave of the original server's master after the backup has been restored.

    mariadb-backup does not check if GTIDs are being used in replication. It takes a shortcut and assumes that if the gtid_slave_pos system variable is non-empty, then it writes the CHANGE MASTER command with the MASTER_USE_GTID option set to slave_pos. Otherwise, it writes the CHANGE MASTER command with the MASTER_LOG_FILE and MASTER_LOG_POS options using the master's binary log file and position. See for more information.

    xtrabackup_slave_info

    If the --slave-info option is provided, this file contains the CHANGE MASTER command that can be used to set up a new server as a slave of the original server's master after the backup has been restored.

    mariadb-backup does not check if GTIDs are being used in replication. It takes a shortcut and assumes that if the system variable is non-empty, then it writes the CHANGE MASTER command with the MASTER_USE_GTID option set to slave_pos. Otherwise, it writes the

    mariadb_backup_galera_info

    If the --galera-info option is provided, this file contains information about a Galera Cluster node's state.

    The file contains the values of the and status variables.

    The values are written in the following format:

    wsrep_local_state_uuid:wsrep_last_committed

    For example:

    d38587ce-246c-11e5-bcce-6bbd0831cc0f:1352215

    xtrabackup_galera_info

    If the --galera-info option is provided, this file contains information about a Galera Cluster node's state.

    The file contains the values of the and status variables.

    The values are written in the following format:

    For example:

    If the backup is an incremental backup, this file contains changed pages for the table.

    If the backup is an incremental backup, this file contains metadata about <table>.delta files. The fields in this file are listed below.

    This field contains either the value of innodb_page_size or the value of the KEY_BLOCK_SIZE table option for the table if the ROW_FORMAT table option for the table is set to COMPRESSED.

    If the ROW_FORMAT table option for this table is set to COMPRESSED, this field contains the value of the compressed page size.

    This field contains the value of the table's space_id.

    This page is licensed: CC BY-SA / Gnu FDL

    mariadb-backup was previously called mariabackup.

    backup-my.cnf

    ib_logfile0

    backup_type

    from_lsn

    to_lsn

    last_lsn

    uuid

    name

    tool_name

    tool_command

    tool_version

    ibbackup_version

    server_version

    start_time

    end_time

    lock_time

    binlog_pos

    innodb_from_lsn

    innodb_to_lsn

    partial

    incremental

    format

    compressed

    <table>.delta

    <table>.delta.meta

    page_size

    zip_size

    space_id

    spinner
    --skip-grant-tables
    Watch Now
    OQGRAPH
    VIDEX
    CONNECT
    CSV
    InnoDB
    MERGE
    MEMORY
    InnoDB
    Mroonga
    MyISAM
    MyRocks
    OQGRAPH
    S3 Storage Engine
    Sequence
    SphinxSE
    Spider
    VIDEX
    Watch Now

    Essential Queries Guide

    Learn how to perform essential SQL operations such as creating tables, inserting data, and using aggregate functions like MAX, MIN, and AVG.

    The Essential Queries Guide offers a concise collection of commonly-used SQL queries. It's designed to help developers and database administrators quickly find syntax and examples for typical database operations, from table creation and data insertion to effective data retrieval and manipulation.

    Creating a Table

    To create new tables:

    CREATE TABLE t1 ( a INT );
    CREATE TABLE t2 ( b INT );
    CREATE TABLE student_tests (
     name CHAR(10), test CHAR(10),
     score TINYINT, test_date DATE
    );

    For more details, see the official CREATE TABLE documentation.

    Inserting Records

    To add data into your tables:

    INSERT INTO t1 VALUES (1), (2), (3);
    INSERT INTO t2 VALUES (2), (4);
    INSERT INTO student_tests
     (name, test, score, test_date) VALUES
     ('Chun', 'SQL', 75, '2012-11-05'),
     ('Chun', 'Tuning', 73, '2013-06-14'),
     ('Esben', 'SQL', 43, '2014-02-11'),
     ('Esben', 'Tuning', 31, '2014-02-09'),
     ('Kaolin', 'SQL', 56, '2014-01-01'),
     ('Kaolin', 'Tuning', 88, '2013-12-29'),
     ('Tatiana', 'SQL', 87, '2012-04-28'),
     ('Tatiana', 'Tuning', 83, '2013-09-30');

    For more information, see INSERT.

    Using AUTO_INCREMENT

    The AUTO_INCREMENT attribute automatically generates a unique identity for new rows.

    Create a table with an AUTO_INCREMENT column:

    When inserting, omit the id field; it will be automatically generated:

    Verify the inserted records:

    For more details, see the documentation.

    To combine rows from two tables based on a related column:

    This type of query is a join. For more details, consult the documentation on .

    To find the maximum value in a column:

    See the documentation. For a grouped example, refer to Finding the Maximum Value and Grouping the Results below.

    To find the minimum value in a column:

    See the documentation.

    To calculate the average value of a column:

    See the documentation.

    To find the maximum value within groups:

    Further details are available in the documentation.

    To sort your query results (e.g., in descending order):

    For more options, see the documentation.

    To find the entire row containing the minimum value of a specific column across all records:

    To retrieve the full record for the maximum value within each group (e.g., highest score per student):

    Use the TIMESTAMPDIFF function to calculate age from a birth date.

    To see the current date (optional, for reference):

    To calculate age as of a specific date (e.g., '2014-08-02'):

    To calculate current age, replace the specific date string (e.g., '2014-08-02') with CURDATE().

    See the documentation for more.

    can store values for use in subsequent queries within the same session.

    Example: Set a variable for the average score and use it to filter results.

    Example: Add an incremental counter to a result set.

    See for more.

    To list all tables in the current database, ordered by their size (data + index) in megabytes:

    To remove duplicate rows based on specific column values, while keeping one instance (e.g., the instance with the highest id).

    This example assumes id is a unique primary key and duplicates are identified by the values in column f1. It keeps the row with the maximum id for each distinct f1 value.

    Setup sample table and data:

    To delete duplicate rows, keeping the one with the highest id for each group of f1 values:

    This query targets rows for deletion (t_del) where their f1 value matches an f1 in a subquery (t_keep) that has duplicates, and their id is less than the maximum id found for that f1 group.

    Verify results after deletion:


    This page is licensed: CC BY-SA / Gnu FDL

    Doing Time Guide

    Understand how to work with date and time values in MariaDB, including data types like DATETIME and TIMESTAMP, and useful temporal functions.

    This guide covers effective ways to work with date and time information in MariaDB. Learn about temporal data types, essential functions for recording current date/time, extracting specific parts, and formatting your date/time values for display or analysis.

    Temporal Data Types

    While dates and times can be stored as character strings, using specific temporal data types allows you to leverage MariaDB's built-in functions for manipulation and formatting.

    • DATE: For dates only. Format: YYYY-MM-DD.

    • TIME: For time only. Format: HHH:MM:SS (hours can range beyond 24).

    • DATETIME: For combined date and time. Format: YYYY-MM-DD HH:MM:SS.

    • TIMESTAMP: Similar to DATETIME, but with a more limited range and automatic update capabilities (not covered here). Range typically from 1970-01-01 00:00:01 UTC to 2038-01-19 03:14:07 UTC. From MariaDB 11.5 (64-bit), this range extends to 2106-02-07.

    • YEAR: For years only. Format: YY or YYYY.

    MariaDB provides several functions to get the current date and time.

    Current Date: Use CURRENT_DATE (no parentheses) or CURDATE() (with parentheses).

    To see the ID of the last inserted row (if the primary key is AUTO_INCREMENT):

    Current Time: Use CURRENT_TIME or CURTIME().

    Current Date and Time (Timestamp): Use CURRENT_TIMESTAMP, NOW(), or SYSDATE(). These functions return the current date and time in YYYY-MM-DD HH:MM:SS format, suitable for DATETIME or TIMESTAMP columns.

    Extracting from DATE types:

    • YEAR(date_column): Extracts the year.

    • MONTH(date_column): Extracts the month number (1-12).

    • DAYOFMONTH(date_column): Extracts the day of the month (1-31). Also DAY()

    (The AS keyword is used to provide an alias for the output column name.)

    Day of the Week:

    • DAYOFWEEK(date_column): Returns the weekday index (1=Sunday, 2=Monday, ..., 7=Saturday).

    • WEEKDAY(date_column): Returns the weekday index (0=Monday, 1=Tuesday, ..., 6=Sunday).

    Example using IF() to determine a billing rate based on the day of the week (Saturday = day 7 for DAYOFWEEK):

    The IF(condition, value_if_true, value_if_false) function allows conditional logic.

    Other Date Part Functions:

    • DAYOFYEAR(date_column): Returns the day of the year (1-366).

    • QUARTER(date_column): Returns the quarter of the year (1-4).

    Example: Selecting sessions in a specific quarter (e.g., Q2):

    User variables can be used for dynamic queries:

    Extracting from TIME types:

    • HOUR(time_column): Extracts the hour.

    • MINUTE(time_column): Extracts the minute.

    • SECOND(time_column): Extracts the second.

    Using EXTRACT() for DATETIME or TIMESTAMP types: The EXTRACT(unit FROM datetime_column) function extracts a specified unit from a date/time value. Common units: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND

    (For details on joining tables, refer to relevant SQL documentation or a guide like "Essential Queries Guide".)

    Using a combined unit:

    Output for HOUR_MINUTE might be like 1303 (for 13:03).

    Wordier Date Formats:

    • MONTHNAME(date_column): Returns the full name of the month (e.g., 'May').

    • DAYNAME(date_column): Returns the full name of the day (e.g., 'Wednesday').

    Example using CONCAT() to combine parts:

    Using DATE_FORMAT(datetime_column, format_string): This function provides extensive formatting options. Syntax: DATE_FORMAT(date_value, 'format_options_and_literals').

    Common format specifiers:

    • %W: Full weekday name

    • %M: Full month name

    • %e: Day of the month, numeric (1-31)

    Example with time:

    For a complete list of options, see the official .

    Using TIME_FORMAT(time_column, format_string): Similar to DATE_FORMAT(), but uses only time-related format options.

    Here, %l is hour (1-12) and %p adds AM/PM.

    • Use Appropriate Data Types: Choose temporal data types (DATE, TIME, DATETIME, TIMESTAMP, YEAR) over string types for date/time data to leverage built-in functions and ensure data integrity.

    • Leverage Built-in Functions: MariaDB offers a rich set of functions for date/time manipulation. Use them within your SQL queries to avoid complex logic in your application code.

    • — the full reference for every function used above

    • and

    This page is licensed: CC BY-SA / Gnu FDL

    Getting Data Guide

    This guide explains the SELECT statement in detail, covering how to retrieve, filter, limit, and sort data from your MariaDB database.

    This guide explains how to retrieve data from MariaDB using the SELECT statement, progressing from basic syntax to more involved queries. Learn to select specific columns, limit results, filter with WHERE, sort with ORDER BY, join tables, and use various helpful options and functions.

    Setup: Creating and Populating Example Tables

    To follow the examples, first create and populate the books and authors tables:

    CREATE OR REPLACE TABLE books (
        isbn CHAR(20) PRIMARY KEY,
        title VARCHAR(50),
        author_id INT,
        publisher_id INT,
        year_pub CHAR(4),
        description TEXT
    );
    
    CREATE OR REPLACE TABLE authors (
        author_id INT AUTO_INCREMENT PRIMARY KEY,
        name_last VARCHAR(50),
        name_first VARCHAR(50),
        country VARCHAR(50)
    );
    
    INSERT INTO authors (name_last, name_first, country) VALUES
      ('Kafka', 'Franz', 'Czech Republic'),
      ('Dostoevsky', 'Fyodor', 'Russia');
    
    INSERT INTO books (title, author_id, isbn, year_pub) VALUES
     ('The Trial', 1, '0805210407', '1995'),
     ('The Metamorphosis', 1, '0553213695', '1995'),
     ('America', 2, '0805210644', '1995'), -- Note: Original data had author_id 2 for 'America', Dostoevsky is author_id 2.
     ('Brothers Karamozov', 2, '0553212168', ''),
     ('Crime & Punishment', 2, '0679420290', ''),
     ('Crime & Punishment', 2, '0553211757', ''),
     ('Idiot', 2, '0192834118', ''),
     ('Notes from Underground', 2, '067973452X', '');

    Basic Data Retrieval

    Selecting All Columns:

    Use * to select all columns from a table.

    SELECT * FROM books;

    Output (example):

    Selecting Specific Columns:

    List the column names separated by commas.

    Output (example):

    Limiting the Number of Rows with LIMIT:

    • To get the first N rows:

      Output (example):

    • To get N rows starting from an offset (offset is 0-indexed):SQL

      Output (example, assuming only 3 more rows exist after offset 5):

    Filtering with WHERE:

    Use the WHERE clause to specify conditions for row selection.

    Output (example):

    Ordering with ORDER BY:

    Use ORDER BY column_name [ASC|DESC] to sort the result set.

    Output (example):

    • ASC (ascending) is the default order. DESC is for descending order.

    • You can order by multiple columns: ORDER BY col1 ASC, col2 DESC.

    • Clause Order: SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT ...

    Joining Tables:

    Use JOIN to combine rows from two or more tables based on a related column.

    Output (example):

    • Alternative JOIN syntax: ... JOIN authors ON books.author_id = authors.author_id .... For more on joins, see the or a "Basic Joins Guide".

    • : Concatenates strings.

    Pattern Matching with LIKE:

    Use in the WHERE clause for pattern matching. % is a wildcard for zero or more characters.

    Output (example, same as above if only Dostoevsky matches):

    Place these modifiers immediately after the SELECT keyword.

    • ALL vs DISTINCT:

      • ALL (default): Returns all rows that meet the criteria.

    • — the full statement reference, including LIMIT, ORDER BY, DISTINCT, and GROUP BY

    This page is licensed: CC BY-SA / Gnu FDL

    MariaDB String Functions Guide

    This guide goes through several built-in string functions in MariaDB, grouping them by similar features, and providing examples of how they might be used.

    MariaDB has many built-in functions that can be used to manipulate strings of data. With these functions, one can format data, extract certain characters, or use search expressions. Good developers should be aware of the string functions that are available. Therefore, in this article we will go through several string functions, grouping them by similar features, and provide examples of how they might be used.

    Formatting

    There are several string functions that are used to format text and numbers for nicer display. A popular and very useful function for pasting together the contents of data fields with text is the CONCAT() function. As an example, suppose that a table called contacts has a column for each sales contact's first name and another for the last name. The following SQL statement would put them together:

    SELECT CONCAT(name_first, ' ', name_last)
    AS Name
    FROM contacts;

    This statement will display the first name, a space, and then the last name together in one column. The AS clause will change the column heading of the results to Name.

    A less used concatenating function is CONCAT_WS(). It will put together columns with a separator between each. This can be useful when making data available for other programs. For instance, suppose we have a program that will import data, but it requires the fields to be separated by vertical bars. We could just export the data, or we could use a SELECT statement like the one that follows in conjunction with an interface written with an API language like Perl:

    The first element above is the separator. The remaining elements are the columns to be strung together.

    If we want to format a long number with commas every three digits and a period for the decimal point (e.g., 100,000.00), we can use the function like so:

    In this statement, the will place a dollar sign in front of the numbers found in the col5 column, which are formatted with commas by . The 2 within the stipulates two decimal places.

    Occasionally, one will want to convert the text from a column to either all upper-case letters or all lower-case letters. In the example that follows, the output of the first column is converted to upper-case and the second to lower-case:

    When displaying data in forms, it's sometimes useful to pad the data displayed with zeros or dots or some other filler. This can be necessary when dealing with columns where the width varies to help the user to see the column limits. There are two functions that may be used for padding: and .

    In this SQL statement, dots are added to the right end of each part number. So a part number of "H200" will display as "H200....", but without the quotes. Each part's description will have under-scores preceding it. A part with a description of "brass hinge" will display as "brass hinge".

    If a column is a data-type, a fixed width column, then it may be necessary to trim any leading or trailing spaces from displays. There are a few functions to accomplish this task. The function will eliminate any leading spaces to the left. So "H200" becomes "H200". For columns with trailing spaces, spaces on the right, will work: "H500" becomes "H500". A more versatile trimming function, though, is . With it one can trim left, right or both. Below are a few examples:

    In the first clause, the padding component is specified; the leading dots are to be trimmed from the output of col1. The trailing spaces are trimmed off of col2—space is the default. Both leading and trailing under-scores are trimmed from col3 above. Unless specified, BOTH is the default. So leading and trailing spaces are trimmed from col4 in the statement here.

    When there is a need to extract specific elements from a column, MariaDB has a few functions that can help. Suppose a column in the table contacts contains the telephone numbers of sales contacts, including the area-codes, but without any dashes or parentheses. The area-code of each could be extracted for sorting with the and the telephone number with the function.

    In the function above, the column telephone is given along with the number of characters to extract, starting from the first character on the left in the column. The function is similar, but it starts from the last character on the right, counting left to capture, in this statement, the last seven characters. In the SQL statement above, area_code is reused to order the results set. To reformat the telephone number, it are necessary to use the function.

    In this SQL statement, the function is employed to assemble some characters and extracted data to produce a common display for telephone numbers (e.g., (504) 555-1234). The first element of the is an opening parenthesis. Next, a is used to get the first three characters of telephone, the area-code. After that a closing parenthesis, along with a space is added to the output. The next element uses the function to extract the telephone number's prefix, starting at the fourth position, for a total of three characters. Then a dash is inserted into the display. Finally, the function extracts the remainder of the telephone number, starting at the seventh position. The functions and are interchangeable and their syntax are the same. By default, for both functions, if the number of characters to capture isn't specified, then it's assumed that the remaining ones are to be extracted.

    There are a few functions in MariaDB that can help in manipulating text. One such function is . With it every occurrence of a search parameter in a string can be replaced. For example, suppose we wanted to replace the title Mrs. with Ms. in a column containing the person's title, but only in the output. The following SQL would do the trick:

    We're using the ever handy function to put together the contact's name with spaces. The function extracts each title and replaces Mrs. with Ms., where applicable. Otherwise, for all other titles, it displays them unchanged.

    If we want to insert or replace certain text from a column (but not all of its contents), we could use the function in conjunction with the function. For example, suppose another contacts table has the contact's title and full name in one column. To change the occurrences of Mrs. to Ms., we could not use since the title is embedded in this example. Instead, we would do the following:

    The first element of the function is the column. The second element which contains the is the position in the string that text is to be inserted. The third element is optional; it states the number of characters to overwrite. In this case, Mrs. which is four characters is overwritten with Ms. (the final element), which is only three. Incidentally, if 0 is specified, then nothing is overwritten, text is inserted only. As for the function, the first element is the column and the second the search text. It returns the position within the column where the text is found. If it's not found, then 0 is returned. A value of 0 for the position in the function negates it and returns the value of name unchanged.

    On the odd chance that there is a need to reverse the content of a column, there's the function. You would just place the column name within the function. Another minor function is the function. With it a string may be repeated in the display:

    The first component of the function above is the string or column to be repeated. The second component states the number of times it's to be repeated.

    The function is used to determine the number of characters in a string. This could be useful in a situation where a column contains different types of information of specific lengths. For instance, suppose a column in a table for a college contains identification numbers for students, faculty, and staff. If student identification numbers have eight characters while others have less, the following will count the number of student records:

    The function above counts the number of rows that meet the condition of the WHERE clause.

    In a statement, an clause can be used to sort a results set by a specific column. However, if the column contains IP addresses, a simple sort may not produce the desired results:

    In the limited results above, the IP address 10.0.2.1 should be second. This happens because the column is being sorted lexically and not numerically. The function will solve this sorting problem.

    Basically, the function will convert IP addresses to regular numbers for numeric sorting. For instance, if we were to use the function in the list of columns in a statement, instead of the WHERE clause, the address 10.0.1.1 would return 167772417, 10.0.11.1 will return 167774977, and 10.0.2.1 the number 167772673. As a complement to , the function will translate these numbers back to their original IP addresses.

    MariaDB is fairly case insensitive, which usually is fine. However, to be able to check by case, the function can be used. It converts the column examined to a string and makes a comparison to the search parameter.

    If there is an exact match, the function returns 0. So if col3 here contains "Text", it won't match. Incidentally, if col3 alphabetically is before the string to which it's compared, a -1 are returned. If it's after it, a 1 is returned.

    When you have list of items in one string, the can be used to pull out a sub-string of data. As an example, suppose we have a column which has five elements, but we want to retrieve just the first two elements. This SQL statement will return them:

    The first component in the function above is the column or string to be picked apart. The second component is the delimiter. The third is the number of elements to return, counting from the left. If we want to grab the last two elements, we would use a negative two to instruct MariaDB to count from the right end.

    There are more string functions available in MariaDB. A few of the functions mentioned here have aliases or close alternatives. There are also functions for converting between ASCII, binary, hexi-decimal, and octal strings. And there are also string functions related to text encryption and decryption that were not mentioned. However, this article has given you a good collection of common string functions that will assist you in building more powerful and accurate SQL statements.

    This page is licensed: CC BY-SA / Gnu FDL

    Troubleshooting Connection Issues Guide

    Diagnose and fix common MariaDB Server connection problems, such as "Can't connect to local server" and access-denied errors, with step-by-step troubleshooting.

    The guide helps diagnose and resolve common issues encountered when connecting to a MariaDB server. Identify causes for errors like 'Can't connect to local server' or access denied messages, and learn steps to effectively troubleshoot these connection problems.

    If you are completely new to MariaDB and relational databases, you may want to start with . Also, ensure you understand the connection parameters discussed in the .

    You receive errors like client error 2002 or client error 2003:

    The MariaDB server process may not be running. Verify with mariadb-admin:

    EXPLAIN
    slow query log
    server system variable
    MyISAM
    MERGE

    Querying from Two Tables on a Common Value (JOIN)

    Finding the Maximum Value

    Finding the Minimum Value

    Finding the Average Value

    Finding the Maximum Value and Grouping the Results

    Ordering Results

    Finding the Row with the Minimum of a Particular Column

    Finding Rows with the Maximum Value of a Column by Group

    Calculating Age

    Using User-Defined Variables

    View Tables in Order of Size

    Removing Duplicates

    AUTO_INCREMENT
    JOINS
    MAX() function
    MIN() function
    AVG() function
    MAX() function
    ORDER BY
    TIMESTAMPDIFF()
    User-defined variables
    User-defined Variables
    spinner
    .
    . Combined units:
    YEAR_MONTH
    ,
    DAY_HOUR
    ,
    HOUR_MINUTE
    , etc.

    %d: Day of the month, 2 digits (01-31)

  • %Y: Year, 4 digits

  • %y: Year, 2 digits

  • %c: Month, numeric (1-12)

  • %r: Time in 12-hour format (hh:mm:ss AM/PM)

  • %T: Time in 24-hour format (hh:mm:ss)

  • %H: Hour (00-23)

  • %h or %I: Hour (01-12)

  • %i: Minutes (00-59)

  • %s or %S: Seconds (00-59)

  • %p: AM or PM

  • Test Queries: When dealing with complex date/time logic or formatting, test your SQL statements directly in a MariaDB client (like the mariadb command-line tool) to verify results before embedding them in applications.

  • Be Aware of Time Zones: TIMESTAMP values are stored in UTC and converted to/from the session's time zone, while DATETIME values are stored "as is" without time zone conversion. Understand how your server and session time zones are configured if working with data across different regions. (Time zone handling is a more advanced topic not fully covered here).

  • Recording Current Date and Time

    Extracting Date and Time Parts

    Formatting Dates and Times for Display

    Tips for Effective Date/Time Handling

    See Also

    DATE_FORMAT() documentation
    Date & Time Functions
    DATE_FORMAT()
    TIME_FORMAT()
    EXTRACT()
    spinner

    Extracting

    Manipulating

    Expression Aids

    Conclusion

    FORMAT()
    CONCAT()
    FORMAT()
    FORMAT()
    VARCHAR
    LPAD()
    RPAD()
    CHAR
    LTRIM()
    RTRIM()
    TRIM()
    TRIM()
    LEFT()
    RIGHT()
    LEFT()
    RIGHT()
    SUBSTRING()
    CONCAT()
    CONCAT()
    LEFT()
    SUBSTRING()
    MID()
    MID()
    SUBSTRING()
    REPLACE()
    CONCAT()
    REPLACE()
    INSERT()
    LOCATE()
    REPLACE()
    INSERT()
    LOCATE()
    LOCATE()
    INSERT()
    REVERSE()
    REPEAT()
    CHAR_LENGTH()
    COUNT()
    SELECT
    ORDER BY
    INET_ATON()
    INET_ATON()
    SELECT
    INET_ATON()
    INET_NTOA()
    STRCMP()
    STRCMP()
    SUBSTRING_INDEX()
    spinner
    LOAD DATA INFILE '/tmp/prospects.txt'
    IGNORE INTO TABLE prospect_contact
    FIELDS TERMINATED BY '|';
    mariadb-dump --user='local_user' --password='local_pass' --no-create-info local_db prospect_contact > /tmp/prospects.sql
    mariadb --user='remote_user' --password='remote_pass' remote_sales_dept < /tmp/prospects.sql
    CREATE TABLE student_details (
     id INT NOT NULL AUTO_INCREMENT, name CHAR(10),
     date_of_birth DATE, PRIMARY KEY (id)
    );
    INSERT INTO student_details (name,date_of_birth) VALUES
     ('Chun', '1993-12-31'),
     ('Esben','1946-01-01'),
     ('Kaolin','1996-07-16'),
     ('Tatiana', '1988-04-13');
    SELECT * FROM student_details;
    +----+---------+---------------+
    | id | name    | date_of_birth |
    +----+---------+---------------+
    |  1 | Chun    | 1993-12-31    |
    |  2 | Esben   | 1946-01-01    |
    |  3 | Kaolin  | 1996-07-16    |
    |  4 | Tatiana | 1988-04-13    |
    +----+---------+---------------+
    SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.b;
    SELECT MAX(a) FROM t1;
    +--------+
    | MAX(a) |
    +--------+
    |      3 |
    +--------+
    SELECT MIN(a) FROM t1;
    +--------+
    | MIN(a) |
    +--------+
    |      1 |
    +--------+
    SELECT AVG(a) FROM t1;
    +--------+
    | AVG(a) |
    +--------+
    | 2.0000 |
    +--------+
    SELECT name, MAX(score) FROM student_tests GROUP BY name;
    +---------+------------+
    | name    | MAX(score) |
    +---------+------------+
    | Chun    |         75 |
    | Esben   |         43 |
    | Kaolin  |         88 |
    | Tatiana |         87 |
    +---------+------------+
    SELECT name, test, score FROM student_tests 
     ORDER BY score DESC; -- Use ASC for ascending order
    +---------+--------+-------+
    | name    | test   | score |
    +---------+--------+-------+
    | Kaolin  | Tuning |    88 |
    | Tatiana | SQL    |    87 |
    | Tatiana | Tuning |    83 |
    | Chun    | SQL    |    75 |
    | Chun    | Tuning |    73 |
    | Kaolin  | SQL    |    56 |
    | Esben   | SQL    |    43 |
    | Esben   | Tuning |    31 |
    +---------+--------+-------+
    SELECT name, test, score FROM student_tests 
     WHERE score = (SELECT MIN(score) FROM student_tests);
    +-------+--------+-------+
    | name  | test   | score |
    +-------+--------+-------+
    | Esben | Tuning |    31 |
    +-------+--------+-------+
    SELECT name, test, score FROM student_tests st1
     WHERE score = (SELECT MAX(st2.score) FROM student_tests st2 WHERE st1.name = st2.name);
    +---------+--------+-------+
    | name    | test   | score |
    +---------+--------+-------+
    | Chun    | SQL    |    75 |
    | Esben   | SQL    |    43 |
    | Kaolin  | Tuning |    88 |
    | Tatiana | SQL    |    87 |
    +---------+--------+-------+
    SELECT CURDATE() AS today;
    +------------+
    | today      |
    +------------+
    | 2014-02-17 | -- Example output; actual date will vary
    +------------+
    SELECT name, date_of_birth, TIMESTAMPDIFF(YEAR, date_of_birth, '2014-08-02') AS age
      FROM student_details;
    +---------+---------------+------+
    | name    | date_of_birth | age  |
    +---------+---------------+------+
    | Chun    | 1993-12-31    |   20 |
    | Esben   | 1946-01-01    |   68 |
    | Kaolin  | 1996-07-16    |   18 |
    | Tatiana | 1988-04-13    |   26 |
    +---------+---------------+------+
    SELECT @avg_score := AVG(score) FROM student_tests;
    +-------------------------+
    | @avg_score:= AVG(score) |
    +-------------------------+
    |            67.000000000 |
    +-------------------------+
    SELECT * FROM student_tests WHERE score > @avg_score;
    +---------+--------+-------+------------+
    | name    | test   | score | test_date  |
    +---------+--------+-------+------------+
    | Chun    | SQL    |    75 | 2012-11-05 |
    | Chun    | Tuning |    73 | 2013-06-14 |
    | Kaolin  | Tuning |    88 | 2013-12-29 |
    | Tatiana | SQL    |    87 | 2012-04-28 |
    | Tatiana | Tuning |    83 | 2013-09-30 |
    +---------+--------+-------+------------+
    SET @count = 0;
    SELECT @count := @count + 1 AS counter, name, date_of_birth FROM student_details;
    +---------+---------+---------------+
    | counter | name    | date_of_birth |
    +---------+---------+---------------+
    |       1 | Chun    | 1993-12-31    |
    |       2 | Esben   | 1946-01-01    |
    |       3 | Kaolin  | 1996-07-16    |
    |       4 | Tatiana | 1988-04-13    |
    +---------+---------+---------------+
    SELECT table_schema AS `DB`, table_name AS `TABLE`,
      ROUND(((data_length + index_length) / 1024 / 1024), 2) `Size (MB)`
      FROM information_schema.TABLES
      WHERE table_schema = DATABASE() -- This clause restricts results to the current database
      ORDER BY (data_length + index_length) DESC;
    +--------------------+---------------------------------------+-----------+
    | DB                 | Table                                 | Size (MB) | -- Example Output
    +--------------------+---------------------------------------+-----------+
    | your_db_name       | some_large_table                      |      7.05 |
    | your_db_name       | another_table                         |      6.59 |
    ...
    +--------------------+---------------------------------------+-----------+
    CREATE TABLE t (id INT, f1 VARCHAR(2));
    INSERT INTO t VALUES (1,'a'), (2,'a'), (3,'b'), (4,'a');
    DELETE t_del FROM t AS t_del
    INNER JOIN (
        SELECT f1, MAX(id) AS max_id
        FROM t
        GROUP BY f1
        HAVING COUNT(*) > 1 -- Identify groups with actual duplicates
    ) AS t_keep ON t_del.f1 = t_keep.f1 AND t_del.id < t_keep.max_id;
    SELECT * FROM t;
    +------+------+
    | id   | f1   |
    +------+------+
    |    3 | b    |
    |    4 | a    |
    +------+------+
    INSERT INTO billable_work (doctor_id, patient_id, session_date)
    VALUES ('1021', '1256', CURRENT_DATE);
    SELECT rec_id, doctor_id, patient_id, session_date
    FROM billable_work
    WHERE rec_id = LAST_INSERT_ID();
    +--------+-----------+------------+--------------+
    | rec_id | doctor_id | patient_id | session_date |
    +--------+-----------+------------+--------------+
    |   2462 | 1021      | 1256       | 2025-05-28   | -- Example date
    +--------+-----------+------------+--------------+
    UPDATE billable_work
    SET session_time = CURTIME()
    WHERE rec_id = '2462';
    
    SELECT patient_id, session_date, session_time
    FROM billable_work
    WHERE rec_id = '2462';
    +------------+--------------+--------------+
    | patient_id | session_date | session_time |
    +------------+--------------+--------------+
    | 1256       | 2025-05-28   | 13:03:22     | -- Example time
    +------------+--------------+--------------+
    SELECT
        MONTH(session_date) AS Month,
        DAYOFMONTH(session_date) AS Day,
        YEAR(session_date) AS Year
    FROM billable_work
    WHERE rec_id = '2462';
    +-------+------+------+
    | Month | Day  | Year |
    +-------+------+------+
    |     5 |   28 | 2025 | -- Example output
    +-------+------+------+
    SELECT
        patient_id AS 'Patient ID',
        session_date AS 'Date of Session',
        IF(DAYOFWEEK(session_date) = 7, 1.5, 1.0) AS 'Billing Rate'
    FROM billable_work
    WHERE rec_id = '2462';
    SELECT patient_id, session_date
    FROM billable_work
    WHERE QUARTER(session_date) = 2;
    SET @target_quarter := 2;
    SELECT patient_id, COUNT(*) AS num_sessions
    FROM billable_work
    WHERE QUARTER(session_date) = @target_quarter AND doctor_id = '1021'
    GROUP BY patient_id;
    SELECT
        HOUR(session_time) AS Hour,
        MINUTE(session_time) AS Minute,
        SECOND(session_time) AS Second
    FROM billable_work
    WHERE rec_id = '2462';
    +------+--------+--------+
    | Hour | Minute | Second |
    +------+--------+--------+
    |   13 |     03 |     22 | -- Example output
    +------+--------+--------+
    SELECT
        patient_name AS Patient,
        EXTRACT(HOUR FROM appointment) AS Hour,
        EXTRACT(MINUTE FROM appointment) AS Minute
    FROM billable_work
    JOIN patients ON billable_work.patient_id = patients.patient_id
    WHERE doctor_id = '1021'
      AND EXTRACT(MONTH FROM appointment) = 5
      AND EXTRACT(DAY FROM appointment) = 28;
    SELECT
        patient_name AS Patient,
        EXTRACT(HOUR_MINUTE FROM appointment) AS AppointmentHM
    FROM billable_work
    JOIN patients ON billable_work.patient_id = patients.patient_id
    WHERE doctor_id = '1021';
    SELECT
        patient_name AS Patient,
        CONCAT(
            DAYNAME(appointment), ' - ',
            MONTHNAME(appointment), ' ',
            DAYOFMONTH(appointment), ', ',
            YEAR(appointment)
        ) AS Appointment
    FROM billable_work
    JOIN patients ON billable_work.patient_id = patients.patient_id
    WHERE doctor_id = '1021' AND DATE(appointment) = '2025-05-28'
    LIMIT 1;
    +-------------------+------------------------------+
    | Patient           | Appointment                  |
    +-------------------+------------------------------+
    | Michael Zabalaoui | Wednesday - May 28, 2025     | -- Example
    +-------------------+------------------------------+
    SELECT
        patient_name AS Patient,
        DATE_FORMAT(appointment, '%W - %M %e, %Y') AS Appointment
    FROM billable_work
    JOIN patients ON billable_work.patient_id = patients.patient_id
    WHERE doctor_id = '1021' AND DATE_FORMAT(appointment, '%c') = 5 -- Filter by month 5 (May)
    LIMIT 1;
    SELECT
        DATE_FORMAT(appointment, '%W - %M %e, %Y at %r') AS Appointment
    FROM billable_work
    LIMIT 1;
    +-------------------------------------------------+
    | Appointment                                     |
    +-------------------------------------------------+
    | Wednesday - May 28, 2025 at 01:03:22 PM         | -- Example
    +-------------------------------------------------+
    SELECT
        patient_name AS Patient,
        TIME_FORMAT(appointment, '%l:%i %p') AS AppointmentTime
    FROM billable_work
    JOIN patients ON billable_work.patient_id = patients.patient_id
    WHERE doctor_id = '1021'
      AND DATE(appointment) = CURDATE();
    +-------------------+-----------------+
    | Patient           | AppointmentTime |
    +-------------------+-----------------+
    | Michael Zabalaoui |     1:03 PM     | -- Example
    +-------------------+-----------------+
    SELECT CONCAT_WS('|', col1, col2, col3)
    FROM table1;
    SELECT CONCAT('$', FORMAT(col5, 2))
    FROM table3;
    SELECT UCASE(col1),
    LCASE(col2)
    FROM table4;
    SELECT RPAD(part_nbr, 8, '.') AS 'Part Nbr.',
    LPAD(description, 15, '_') AS Description
    FROM catalog;
    SELECT TRIM(LEADING '.' FROM col1),
    TRIM(TRAILING FROM col2),
    TRIM(BOTH '_' FROM col3),
    TRIM(col4)
    FROM table5;
    SELECT LEFT(telephone, 3) AS area_code,
    RIGHT(telephone, 7) AS tel_nbr
    FROM contacts
    ORDER BY area_code;
    SELECT CONCAT('(', LEFT(telephone, 3), ') ',
    SUBSTRING(telephone, 4, 3), '-',
    MID(telephone, 7)) AS 'Telephone Number'
    FROM contacts
    ORDER BY LEFT(telephone, 3);
    SELECT CONCAT(REPLACE(title, 'Mrs.', 'Ms.'),
    ' ', name_first, ' ', name_last) AS Name
    FROM contacts;
    SELECT INSERT(name, LOCATE(name, 'Mrs.'), 4, 'Ms.') 
    FROM contacts;
    SELECT REPEAT(col1, 2)
    FROM table1;
    SELECT COUNT(school_id)
    AS 'Number of Students'
    FROM table8
    WHERE CHAR_LENGTH(school_id)=8;
    SELECT ip_address 
    FROM computers WHERE server='Y' 
    ORDER BY ip_address LIMIT 3;
    
    +-------------+
    | ip_address  |
    +-------------+
    | 10.0.1.1    |
    | 10.0.11.1   |
    | 10.0.2.1    |
    +-------------+
    SELECT ip_address 
    FROM computers WHERE server='Y' 
    ORDER BY INET_ATON(ip_address) LIMIT 3;
    SELECT col1, col2 
    FROM table6 
    WHERE STRCMP(col3, 'text')=0;
    SELECT SUBSTRING_INDEX(col4, '|', 2)
    FROM table7;
    xtrabackup_binlog_pos_innodb
    with the
    --no-lock
    option is that no DDL or modification of non-transactional tables should be done during the backup. If the last event in the binlog is a DDL/non-transactional update, the coordinates in the file
    xtrabackup_binlog_pos_innodb
    are too old. But as long as only InnoDB updates are done during the backup, the coordinates are correct.
    CHANGE MASTER
    command with the
    MASTER_LOG_FILE
    and
    MASTER_LOG_POS
    options using the master's binary log file and position. See
    for more information.
    backup_type = full-backuped
    from_lsn = 0
    to_lsn = 1635102
    last_lsn = 1635102
    recover_binlog_info = 0
    wsrep_local_state_uuid:wsrep_last_committed
    d38587ce-246c-11e5-bcce-6bbd0831cc0f:1352215
    gtid_current_pos
    --no-lock
    MDEV-19264
    gtid_slave_pos
    mariadb-bin.000096 568 0-1-2
    MDEV-19264
    . MariaDB generally processes
    WHERE
    , then
    ORDER BY
    , then
    LIMIT
    .
    AS alias_name
    :
    Assigns an alias to an output column.
    DISTINCT: Returns only unique rows for the selected columns. If multiple identical rows are found for the specified columns, only the first one is displayed.

    Output (example, showing one "Crime & Punishment"):

  • HIGH_PRIORITY:

    Gives the SELECT statement higher priority over concurrent data modification statements (use with caution as it can impact write performance).

    SQL

    SELECT DISTINCT HIGH_PRIORITY title
    FROM books
    JOIN authors USING (author_id)
    WHERE name_last = 'Dostoevsky'
    ORDER BY title;
  • SQL_CALC_FOUND_ROWS and FOUND_ROWS():

    To find out how many rows a query would have returned without a LIMIT clause, use SQL_CALC_FOUND_ROWS in your SELECT statement, and then execute SELECT FOUND_ROWS(); immediately after.

    SELECT SQL_CALC_FOUND_ROWS isbn, title
    FROM books
    JOIN authors USING (author_id)
    WHERE name_last = 'Dostoevsky'
    ORDER BY title -- Order before limit to ensure consistent FOUND_ROWS() for a given query logic
    LIMIT 5;

    Output (example for the first query):

    Then, to get the total count:

    Output (example, if 6 Dostoevsky books in total):

    The value from is temporary and specific to the current session.

  • A MariaDB Primer and MariaDB Basics
    +------------+------------------------+-----------+--------------+----------+-------------+
    | isbn       | title                  | author_id | publisher_id | year_pub | description |
    +------------+------------------------+-----------+--------------+----------+-------------+
    | 0192834118 | Idiot                  |         2 |         NULL |          | NULL        |
    | 0553211757 | Crime & Punishment     |         2 |         NULL |          | NULL        |
    ... (other rows)
    | 0805210644 | America                |         2 |         NULL | 1995     | NULL        |
    +------------+------------------------+-----------+--------------+----------+-------------+
    8 rows in set (0.001 sec)
    SELECT isbn, title, author_id FROM books;
    +------------+------------------------+-----------+
    | isbn       | title                  | author_id |
    +------------+------------------------+-----------+
    | 0192834118 | Idiot                  |         2 |
    | 0553211757 | Crime & Punishment     |         2 |
    ... (other rows)
    +------------+------------------------+-----------+
    8 rows in set (0.001 sec)
    SELECT isbn, title, author_id FROM books LIMIT 5;
    +------------+--------------------+-----------+
    | isbn       | title              | author_id |
    +------------+--------------------+-----------+
    | 0192834118 | Idiot              |         2 |
    | 0553211757 | Crime & Punishment |         2 |
    | 0553212168 | Brothers Karamozov |         2 |
    | 0553213695 | The Metamorphosis  |         1 |
    | 0679420290 | Crime & Punishment |         2 |
    +------------+--------------------+-----------+
    5 rows in set (0.001 sec)
    SELECT isbn, title, author_id FROM books LIMIT 5, 10; -- Skip 5 rows, show next 10 (or fewer if less remain)
    +------------+------------------------+-----------+
    | isbn       | title                  | author_id |
    +------------+------------------------+-----------+
    | 067973452X | Notes from Underground |         2 |
    | 0805210407 | The Trial              |         1 |
    | 0805210644 | America                |         2 |
    +------------+------------------------+-----------+
    3 rows in set (0.001 sec)
    SELECT isbn, title
    FROM books
    WHERE author_id = 2
    LIMIT 5;
    +------------+------------------------+
    | isbn       | title                  |
    +------------+------------------------+
    | 0192834118 | Idiot                  |
    | 0553211757 | Crime & Punishment     |
    | 0553212168 | Brothers Karamozov     |
    | 0679420290 | Crime & Punishment     |
    | 067973452X | Notes from Underground |
    +------------+------------------------+
    5 rows in set (0.000 sec)
    SELECT isbn, title
    FROM books
    WHERE author_id = 2
    ORDER BY title ASC
    LIMIT 5;
    +------------+--------------------+
    | isbn       | title              |
    +------------+--------------------+
    | 0805210644 | America            |
    | 0553212168 | Brothers Karamozov |
    | 0553211757 | Crime & Punishment |
    | 0679420290 | Crime & Punishment |
    | 0192834118 | Idiot              |
    +------------+--------------------+
    5 rows in set (0.001 sec)
    SELECT isbn, title, CONCAT(name_first, ' ', name_last) AS author
    FROM books
    JOIN authors USING (author_id) -- Assumes 'author_id' column exists in both tables
    WHERE name_last = 'Dostoevsky'
    ORDER BY title ASC
    LIMIT 5;
    +------------+--------------------+-------------------+
    | isbn       | title              | author            |
    +------------+--------------------+-------------------+
    | 0805210644 | America            | Fyodor Dostoevsky |
    | 0553212168 | Brothers Karamozov | Fyodor Dostoevsky |
    | 0553211757 | Crime & Punishment | Fyodor Dostoevsky |
    | 0679420290 | Crime & Punishment | Fyodor Dostoevsky |
    | 0192834118 | Idiot              | Fyodor Dostoevsky |
    +------------+--------------------+-------------------+
    5 rows in set (0.00 sec)
    SELECT isbn, title, CONCAT(name_first, ' ', name_last) AS author
    FROM books
    JOIN authors USING (author_id)
    WHERE name_last LIKE 'Dostoevsk%'
    ORDER BY title ASC
    LIMIT 5;
    +------------+--------------------+-------------------+
    | isbn       | title              | author            |
    +------------+--------------------+-------------------+
    | 0805210644 | America            | Fyodor Dostoevsky |
    | 0553212168 | Brothers Karamozov | Fyodor Dostoevsky |
    | 0553211757 | Crime & Punishment | Fyodor Dostoevsky |
    | 0679420290 | Crime & Punishment | Fyodor Dostoevsky |
    | 0192834118 | Idiot              | Fyodor Dostoevsky |
    +------------+--------------------+-------------------+
    5 rows in set (0.001 sec)

    Filtering and Ordering Results

    Working with Multiple Tables (JOINs) and Functions

    SELECT Statement Modifiers

    See Also

    JOIN Syntax documentation
    CONCAT(str1, str2, ...)
    LIKE
    SELECT
    JOIN Syntax
    spinner
    SELECT DISTINCT title
    FROM books
    JOIN authors USING (author_id)
    WHERE name_last = 'Dostoevsky'
    ORDER BY title;
    +------------------------+
    | title                  |
    +------------------------+
    | America                |
    | Brothers Karamozov     |
    | Crime & Punishment     |
    | Idiot                  |
    | Notes from Underground |
    +------------------------+
    If the server isn't running, start it using the method applicable to your environment.

    The server is running, but not on the specified host, port, socket, pipe, or protocol. Verify your connection parameters.

    • Socket File Mismatch (Unix): The socket file path might be non-standard or inconsistent between server and client configurations.

      • Check your configuration file. Ensure the socket option has the identical value for both server and client.

      • To find the running Unix socket file, try this command:

        $ netstat -ln | grep mysqld

        Example output:

    • See also: .

    You can connect locally, but not from a remote machine, possibly seeing errors like this:

    You can use telnet (if available) to test basic network connectivity to the port:

    A "Connection refused" message from telnet indicates a network or firewall issue, or that MariaDB is not listening for TCP/IP connections or on that specific interface/port.

    The perror utility can interpret OS error codes:

    Example output:

    By default, MariaDB often does not accept remote TCP/IP connections, or is bound only to localhost (127.0.0.1).

    Solution: See Configuring MariaDB for Remote Client Access for detailed instructions on how to enable remote connections by adjusting the bind-address server variable and ensuring user accounts are configured correctly for remote hosts.

    Connection is established, but authentication fails (for instance, "Access denied for user...").

    • Unix Socket Authentication: On Unix-like systems, the unix_socket authentication plugin is enabled by default for local connections via the Unix socket file. This plugin uses operating system user credentials.

      • See the unix_socket authentication plugin documentation for connection instructions and how to switch to password-based authentication if needed.

      • For an overview of authentication changes in MariaDB 10.4, see Authentication from MariaDB 10.4.

    • Incorrect Username/Host Combination: Authentication is specific to a username@host combination. For example, 'user1'@'localhost' is distinct from 'user1'@'166.78.144.191'. Ensure the user account exists for the host from which you are connecting.

      • See for details on granting permissions.

    • Password Hashing: When setting or changing passwords using SET PASSWORD, ensure the PASSWORD() function is used if the server expects hashed passwords.

      • Example: SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass');

    You can run regular queries, but get authentication or permission errors when using SELECT ... INTO OUTFILE, SELECT ... INTO DUMPFILE, or LOAD DATA INFILE.

    • These operations require the FILE privilege on the server.

    • Solution: Grant the necessary FILE privilege to the user. See the GRANT article.

    You can connect to the MariaDB server, but attempting to issue the USE command or query a specific database results in an error:

    Or, connecting with mariadb -u user -p db1 works, but mariadb -u user -p db2 fails for db2.

    • The user account has not been granted sufficient privileges for that particular database.

    • Solution: Grant the required privileges (e.g., SELECT, INSERT, etc.) on the specific database to the user. See GRANT.

    Unexpected connection behavior, or parameter usage that you didn't explicitly provide on the command line.

    • Option files (for instance, my.cnf, .my.ini) or environment variables (for instance, MYSQL_HOST) might be supplying incorrect parameters, or overriding connection parameters.

    • Troubleshooting:

      • Check the values in any option files read by your client. See and the documentation for the specific client you are using (listed under ).

      • You can often suppress the reading of default option files by using a --no-defaults option (if supported by the client):

    You cannot connect to a running server because the root (or other administrative) password is lost or unknown.

    • Solution: You can start the MariaDB server with the --skip-grant-tables option. This bypasses the privilege system, granting full access. Use this with extreme caution and only temporarily.

      1. Stop the MariaDB server.

      2. Restart the server manually from the command line, adding the --skip-grant-tables option.

      3. Connect to the server (no password is required for root@localhost).

      4. Change the password for the account you're connecting with (for example, root):

      5. Stop the server, and restart it normally (without --skip-grant-tables).

    Starting with MariaDB 10.4, the default security model for Linux installations uses the unix_socket authentication plugin. This means the MariaDB root user is tied to your system's root user.

    • The Problem: If you try to connect using mariadb -u root -p, the server may reject you because it is looking for your operating system identity, not a password.

    • The Solution: Instead of a password, use sudo:

      sudo mariadb
    • Why this works: The server recognizes you have sudo (administrative) privileges on the machine and automatically logs you into the MariaDB root account without requiring a separate database password.

    You've created a user like 'melisa'@'%' but cannot log in as melisa when connecting from localhost.

    Example output showing the problem:

    • The MariaDB user authentication prioritizes more specific host matches. If an anonymous user (''@'localhost') exists, it can take precedence over 'melisa'@'%' when connecting from localhost.

    • Solutions:

      1. Create a specific user for localhost:

      2. Remove the anonymous user for localhost (use with caution):

        Ensure this doesn't break other intended anonymous access, if any.

    In this video tutorial, the MariaDB team explains the fundamental changes to the security model introduced in version 10.4, specifically regarding how the root user and local connections are handled.

    Core Topics Covered:

    • The "No Password" Default: Explains why, in MariaDB 10.4 and later, the root user does not have a password by default on many Linux distributions.

    • Unix Socket Authentication: A walkthrough of the unix_socket plugin. This plugin allows the OS-level root user to log in to the MariaDB root account without a password, as security is verified by the operating system identity.

    • The mysql.global_priv table: Introduction of the new table that replaces the old mysql.user table for storing privileges, and how this change simplifies managing multiple authentication methods for a single user.

    • Switching Authentication Methods: Practical steps on how to move from socket-based authentication back to traditional password-based authentication (using the mysql_native_password plugin) if your environment requires it.

    Key Takeaway for Troubleshooting:

    If you are receiving an Access Denied error while trying to log in as root despite using a password you believe is correct, the video demonstrates that your server is likely expecting Unix Socket authentication. In this case, you should use sudo mariadb rather than mariadb -u root -p.

    • CREATE USER

    • GRANT

    • Authentication

    • Authentication from MariaDB 10 4 (video • 20 minutes • 2020)

    This page is licensed: CC BY-SA / Gnu FDL

    ERROR 2002 (HY000): Can't connect to local MySQL server through
      socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")
    mariadb -u someuser -p --port=3307 --protocol=tcp
    ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost'
      (111 "Connection refused")
    $ mariadb-admin status      
    mariadb-admin: connect to server at 'localhost' failed
    error: 'Can't connect to local server through socket '/tmp/mysql.sock' (2)'
    Check that mariadbd is running and that the socket: '/tmp/mysql.sock' exists!

    Server Not Running or Incorrect Location

    Symptoms

    Causes & Solutions

    Server Not Running

    A MariaDB Primer
    Connection Parameters Guide
    $ mariadb --host=myhost --protocol=tcp --port=3306 test
    ERROR 2002 (HY000): Can't connect to MySQL server on 'myhost' (115)
    $ telnet myhost 3306
    $ perror 115
    OS error code 115: Operation now in progress
    USE test;
    ERROR 1044 (42000): Access denied for user 'youruser'@'yourhost' to database 'test'
    -- User created with '%' host
    CREATE USER 'melisa'@'%' IDENTIFIED BY 'password';
    
    -- Checking users in mysql.user table
    SELECT user, host FROM mysql.user WHERE user='melisa' OR user='';
    +--------+-----------+
    | user   | host      |
    +--------+-----------+
    | melisa | %         |
    |        | localhost | -- An anonymous user for localhost
    +--------+-----------+

    Incorrect Parameters

    Unable to Connect from a Remote Location

    Symptoms

    Causes & Solutions

    Authentication Problems

    Symptoms

    Causes & Solutions

    Problems Exporting Query Results or Loading Data

    Symptoms

    Causes & Solutions

    Access Denied to a Specific Database

    Symptoms

    Causes & Solutions

    Issues Due to Option Files or Environment Variables

    Symptoms

    Causes & Solutions

    Unable to Connect / Lost Root Password

    Symptoms

    Causes & Solutions

    Before doing this, particularly if you cannot connect to a freshly installed MariaDB server, see if the next solution can solve your problem.

    Quick Fix: Access Denied for 'root'@'localhost'?

    Do not use this as a permanent solution.

    Rather than that, use it as a one-off, to be able to connect to the MariaDB Server at all. Once logged in, create a proper user, like 'myuser'@'localhost', or even 'myadmin'@'localhost'. Then, the necessary privileges to that user. An administrative user, comparable to root, should have privileges to access every object in your database, by running this query:

    localhost vs. % Wildcard Host Issues

    Symptoms

    Causes & Solutions

    MariaDB Authentication Tutorial

    See Also

    spinner
    InnoDB
    Memory
    MyISAM
    MyRocks
    S3
    Spider
    Watch Now

    CREATE PROCEDURE

    Complete CREATE PROCEDURE guide for MariaDB. Complete reference documentation for implementation, configuration, and usage with comprehensive examples and.

    Syntax

    CREATE
        [OR REPLACE]
        [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
        PROCEDURE [IF NOT EXISTS] sp_name ([proc_parameter[,...]])
        [characteristic ...] routine_body
    
    proc_parameter:
        [ OUT | INOUT | IN OUT] param_name type |
        [ IN ] param_name type [DEFAULT value or expression]
    
    type:
    
    Railroad diagram of CREATE PROCEDURE — equivalent to the BNF above
    Railroad diagram of proc_parameter
    Railroad diagram of characteristic

    The IN OUT parameter works only in Oracle mode.

    CREATE
        [OR REPLACE]
        [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
        PROCEDURE [IF NOT EXISTS] sp_name ([proc_parameter[,...]])
        [characteristic ...] routine_body
    
    proc_parameter:
        [ IN | OUT | INOUT ] param_name type
    
    type:
        Any valid MariaDB data type
    
    characteristic:
        LANGUAGE SQL
      | [NOT] DETERMINISTIC
      | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
      | SQL SECURITY { DEFINER | INVOKER }
      | COMMENT 'string'
    
    routine_body:
        Valid SQL procedure statement

    Description

    Creates a stored procedure. By default, a routine is associated with the default database. To associate the routine explicitly with a given database, specify the name as db_name.sp_name when you create it.

    When the routine is invoked, an implicit USE`` db_name is performed (and undone when the routine terminates). The causes the routine to have the given default database while it executes. USE statements within stored routines are disallowed.

    When a stored procedure has been created, you invoke it by using the CALL statement (see ).

    To execute the CREATE PROCEDURE statement, it is necessary to have the CREATE ROUTINE privilege. By default, MariaDB automatically grants the ALTER ROUTINE and EXECUTE privileges to the routine creator. See also .

    The DEFINER and SQL SECURITY clauses specify the security context to be used when checking access privileges at routine execution time, as described . Requires the privilege.

    If the routine name is the same as the name of a built-in SQL function, you must use a space between the name and the following parenthesis when defining the routine, or a syntax error occurs. This is also true when you invoke the routine later. For this reason, we suggest that it is better to avoid reusing the names of existing SQL functions for your own stored routines.

    The IGNORE_SPACE SQL mode applies to built-in functions, not to stored routines. It is always allowable to have spaces after a routine name, regardless of whether IGNORE_SPACE is enabled.

    The parameter list enclosed within parentheses must always be present. If there are no parameters, an empty parameter list of () should be used. Parameter names are not case sensitive.

    Each parameter can be declared to use any valid data type, except that the COLLATE attribute cannot be used.

    For valid identifiers to use as procedure names, see .

    • One can't use OR REPLACE together with IF EXISTS.

    If the IF NOT EXISTS clause is used, then the procedure will only be created if a procedure with the same name does not already exist. If the procedure already exists, then a warning are triggered by default.

    Each parameter is an IN parameter by default. To specify otherwise for a parameter, use the keyword OUT or INOUT before the parameter name.

    An IN parameter passes a value into a procedure. The procedure might modify the value, but the modification is not visible to the caller when the procedure returns. An OUT parameter passes a value from the procedure back to the caller. Its initial value is NULL within the procedure, and its value is visible to the caller when the procedure returns. An INOUT parameter is initialized by the caller, can be modified by the procedure, and any change made by the procedure is visible to the caller when the procedure returns.

    For each OUT or INOUT parameter, pass a user-defined variable in theCALL statement that invokes the procedure so that you can obtain its value when the procedure returns. If you are calling the procedure from within another stored procedure or function, you can also pass a routine parameter or local routine variable as an IN or INOUT parameter.

    As of , each parameter can be defined as having a default value or expression. This can be useful if needing to add extra parameters to a procedure which is already in use.

    DETERMINISTIC and NOT DETERMINISTIC apply only to . Specifying DETERMINISTC or NON-DETERMINISTIC in procedures has no effect. The default value is NOT DETERMINISTIC. Functions are DETERMINISTIC when they always return the same value for the same input. For example, a truncate or substring function. Any function involving data, therefore, is always NOT DETERMINISTIC.

    CONTAINS SQL, NO SQL, READS SQL DATA, and MODIFIES SQL DATA are informative clauses that tell the server what the function does. MariaDB does not check in any way whether the specified clause is correct. If none of these clauses are specified, CONTAINS SQL is used by default.

    MODIFIES SQL DATA means that the function contains statements that may modify data stored in databases. This happens if the function contains statements like , , , or DDL.

    READS SQL DATA means that the function reads data stored in databases but does not modify any data. This happens if statements are used, but there no write operations are executed.

    CONTAINS SQL means that the function contains at least one SQL statement, but it does not read or write any data stored in a database. Examples include or .

    NO SQL means nothing, because MariaDB does not currently support any language other than SQL.

    The routine_body consists of a valid SQL procedure statement. This can be a simple statement such as or , or it can be a compound statement written using . Compound statements can contain declarations, loops, and other control structure statements. See for syntax details.

    MariaDB allows routines to contain DDL statements, such as CREATE and DROP. MariaDB also allows (but not ) to contain SQL transaction statements such as COMMIT.

    For additional information about statements that are not allowed in stored routines, see .

    For information about invoking from within programs written in a language that has a MariaDB/MySQL interface, see .

    If the optional OR REPLACE clause is used, it acts as a shortcut for the following statements, with the exception that any existing for the procedure are not dropped:

    MariaDB stores the system variable setting that is in effect at the time a routine is created and always executes the routine with this setting in force, regardless of the server in effect when the routine is invoked.

    Procedure parameters can be declared with any character set/collation. If the character set and collation are not specifically set, the database defaults at the time of creation are used. If the database defaults change at a later stage, the stored procedure character set/collation will not be changed at the same time; the stored procedure needs to be dropped and recreated to ensure the same character set/collation as the database is used.

    A subset of Oracle's PL/SQL language is supported in addition to the traditional SQL/PSM-based MariaDB syntax. See for details on changes when running Oracle mode.

    The following example shows a simple stored procedure that uses an OUT parameter. It uses the DELIMITER command to set a new delimiter for the duration of the process — see .

    Character set and collation:

    CREATE OR REPLACE:

    This page is licensed: CC BY-SA / Gnu FDL

    spinner
    spinner
    spinner
    FOUND_ROWS()
    +------------+------------------------+
    | isbn       | title                  |
    +------------+------------------------+
    | 0805210644 | America                |
    | 0553212168 | Brothers Karamozov     |
    | 0553211757 | Crime & Punishment     |
    | 0679420290 | Crime & Punishment     |
    | 0192834118 | Idiot                  |
    +------------+------------------------+
    5 rows in set (0.001 sec)
    SELECT FOUND_ROWS();
    +--------------+
    | FOUND_ROWS() |
    +--------------+
    |            6 |
    +--------------+
    1 row in set (0.000 sec)
    Rather than: SET PASSWORD FOR 'bob'@'%.loc.gov' = 'newpass'; (which might store the password as plain text, potentially leading to issues depending on the authentication plugin).
    GRANT ALL ON *.* to 'myadmin'@'localhost' IDENTIFIED BY '(your_password)' WITH GRANT OPTION

    When done, log out, then log in again, using your newly created user. This is now possible without using the sudo workaround:

    mariadb --user myadmin --password (specify your_password when prompted)

    unix  2      [ ACC ]     STREAM     LISTENING     33209505 /var/run/mysqld/mysqld.sock
    $ mariadb --no-defaults ...
    SET PASSWORD FOR 'root'@'localhost' = PASSWORD('your_new_strong_password');
    CREATE USER 'melisa'@'localhost' IDENTIFIED BY 'password_for_melisa_localhost';
    GRANT ALL PRIVILEGES ON yourdatabase.* TO 'melisa'@'localhost'; -- Grant necessary privileges
    DROP USER ''@'localhost';
    Troubleshooting Installation Issues
    GRANT
    Configuring MariaDB with Option Files
    Clients and Utilities
    Error 1698: Access denied for user
    grant

  • Any valid MariaDB data type
    characteristic:
    LANGUAGE SQL
    | [NOT] DETERMINISTIC
    | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
    | SQL SECURITY { DEFINER | INVOKER }
    | COMMENT 'string'
    routine_body:
    Valid SQL procedure statement
    DROP PROCEDURE IF EXISTS name;
    CREATE PROCEDURE name ...;
    DELIMITER //
    
    CREATE PROCEDURE simpleproc (OUT param1 INT)
     BEGIN
      SELECT COUNT(*) INTO param1 FROM t;
     END;
    //
    
    DELIMITER ;
    
    CALL simpleproc(@a);
    
    SELECT @a;
    +------+
    | @a   |
    +------+
    |    1 |
    +------+
    DELIMITER //
    
    CREATE PROCEDURE simpleproc2 (
      OUT param1 CHAR(10) CHARACTER SET 'utf8' COLLATE 'utf8_bin'
    )
     BEGIN
      SELECT CONCAT('a'),f1 INTO param1 FROM t;
     END;
    //
    
    DELIMITER ;
    DELIMITER //
    
    CREATE PROCEDURE simpleproc2 (
      OUT param1 CHAR(10) CHARACTER SET 'utf8' COLLATE 'utf8_bin'
    )
     BEGIN
      SELECT CONCAT('a'),f1 INTO param1 FROM t;
     END;
    //
    ERROR 1304 (42000): PROCEDURE simpleproc2 already exists
    
    DELIMITER ;
    
    DELIMITER //
    
    CREATE OR REPLACE PROCEDURE simpleproc2 (
      OUT param1 CHAR(10) CHARACTER SET 'utf8' COLLATE 'utf8_bin'
    )
     BEGIN
      SELECT CONCAT('a'),f1 INTO param1 FROM t;
     END;
    //
    ERROR 1304 (42000): PROCEDURE simpleproc2 already exists
    
    DELIMITER ;
    Query OK, 0 rows affected (0.03 sec)

    Things to be Aware of With CREATE OR REPLACE

    CREATE PROCEDURE IF NOT EXISTS

    IN/OUT/INOUT/IN OUT

    DEFAULT value or expression

    DETERMINISTIC/NOT DETERMINISTIC

    CONTAINS SQL/NO SQL/READS SQL DATA/MODIFIES SQL DATA

    Invoking stored procedure from within programs

    OR REPLACE

    sql_mode

    Character Sets and Collations

    Oracle Mode

    Examples

    See Also

    CALL
    Stored Routine Privileges
    here
    SET USER
    Identifier Names
    functions
    DELETE
    UPDATE
    INSERT
    REPLACE
    SELECT
    SET
    DO
    SELECT
    INSERT
    BEGIN and END
    Programmatic and Compound Statements
    stored procedures
    stored functions
    Stored Routine Limitations
    stored procedures
    CALL
    privileges
    sql_mode
    SQL mode
    Delimiters in the mariadb client
    Identifier Names
    Stored Procedure Overview
    ALTER PROCEDURE
    DROP PROCEDURE
    spinner
    SHOW CREATE PROCEDURE
    SHOW PROCEDURE STATUS
    Stored Routine Privileges
    Information Schema ROUTINES Table
    spinner

    MariaDB Enterprise Backup

    This page details MariaDB Enterprise Backup, an enhanced version of mariadb-backup with enterprise-specific optimizations and support.

    Overview

    Regular and reliable backups are essential to successful recovery of mission critical applications. MariaDB Enterprise Server backup and restore operations are performed using MariaDB Enterprise Backup, an enterprise-build of MariaDB Backup.

    MariaDB Enterprise Backup is compatible with MariaDB Enterprise Server.

    Storage Engines and Backup Types

    MariaDB Backup creates a file-level backup of data from the MariaDB Community Server data directory. This backup includes temporal data, and the encrypted and unencrypted tablespaces of supported storage engines (e.g., InnoDB, MyRocks, Aria).

    MariaDB Enterprise Server implements:

    • Full backups, which contain all data in the database.

    • Incremental backups, which contain modifications since the last backup.

    • Partial backups, which contain a subset of the tables in the database.

    Backup support is specific to storage engines. All supported storage engines enable full backup. The InnoDB storage engine additionally supports incremental backup.

    Note: MariaDB Enterprise Backup does not support backups of MariaDB ColumnStore. Backup of MariaDB ColumnStore can be performed using . Backup of data ingested to MariaDB ColumnStore can also occur pre-ingestion, such as in the case of HTAP where backup could occur of transactional data in MariaDB Enterprise Server, and restore of data to MariaDB ColumnStore would then occur through reprocessing..

    A feature of MariaDB Enterprise Backup and MariaDB Enterprise Server, non-blocking backups minimize workload impact during backups. When MariaDB Enterprise Backup connects to MariaDB Enterprise Server, staging operations are initiated to protect data during read.

    Non-blocking backup functionality differs from historical backup functionality in the following ways:

    • MariaDB Enterprise Backup in MariaDB Enterprise Server includes enterprise-only optimizations to backup staging, including DDL statement tracking, which reduces lock-time during backups.

    • MariaDB Backup in MariaDB Community Server 10.4 and later will block writes, log tables, and statistics.

    • Older MariaDB Community Server releases used FLUSH TABLES WITH READ LOCK, which closed open tables and only allowed tables to be reopened with a read lock during the duration of backups.

    MariaDB Enterprise Backup creates complete or incremental backups of MariaDB Enterprise Server data, and is also used to restore data from backups produced using MariaDB Enterprise Backup.

    Full backups produced using MariaDB Enterprise Server are not initially point-in-time consistent, and an attempt to restore from a raw full backup will cause InnoDB to crash to protect the data.

    Incremental backups produced using MariaDB Enterprise Backup contain only the changes since the last backup and cannot be used standalone to perform a restore.

    To restore from a backup, you first need to prepare the backup for point-in-time consistency using the --prepare command:

    • Running the --prepare command on a full backup synchronizes the tablespaces, ensuring that they are point-in-time consistent and ready for use in recovery.

    • Running the --prepare command on an incremental backup synchronizes the tablespaces and also applies the updated data into the previous full backup, making it a complete backup ready for use in recovery.

    • Running the --prepare

    When MariaDB Enterprise Backup restores from a backup, it copies or moves the backup files into the MariaDB Enterprise Server data directory, as defined by the datadir system variable.

    For MariaDB Backup to safely restore data from full and incremental backups, the data directory must be empty. One way to achieve this is to move the data directory aside to a unique directory name:

    1. Make sure that the Server is stopped.

    2. Move the data directory to a unique name (e.g., /var/lib/mysql-2020-01-01) OR remove the old data directory (depending on how much space you have available).

    3. Create a new (empty) data directory (e.g., mkdir /var/lib/mysql).

    When MariaDB Backup performs a backup operation, it not only copies files from the data directory but also connects to the running MariaDB Enterprise Server.

    This connection to MariaDB Enterprise Server is used to manage locks that prevent the Server from writing to a file while being read for a backup.

    MariaDB Backup establishes this connection based on the user credentials specified with the --user and --password options when performing a backup.

    It is recommended that a dedicated user be created and authorized to perform backups.

    MariaDB Backup requires this user to have the RELOAD, PROCESS, LOCK TABLES, and REPLICATION CLIENT privileges.

    In the above example, MariaDB Backup would run on the local system that runs MariaDB Enterprise Server. Where backups may be run against a remote server, the user authentication and authorization should be adjusted.

    While MariaDB Backup requires a user for backup operations, no user is required for restore operations since restores occur while MariaDB Enterprise Server is not running.

    MariaDB Backup requires this user to have the RELOAD, PROCESS, LOCK TABLES, and REPLICATION CLIENT privileges.

    Full backups performed with MariaDB Backup contain all table data present in the database.

    When performing a full backup, MariaDB Backup makes a file-level copy of the MariaDB Enterprise Server data directory. This backup omits log data such as the binary logs (binlog), error logs, general query logs, and slow query logs.

    When you perform a full backup, MariaDB Backup writes the backup to the --target-dir path. The directory must be empty or non-existent and the operating system user account must have permission to write to that directory. A database user account is required to perform the backup.

    The version of mariadb-backup or mariadb-backup should be the same version as the MariaDB Enterprise Server version. When the version does not match the server version, errors can sometimes occur, or the backup can sometimes be unusable.

    To create a backup, execute mariadb-backup or mariadb-backup with the --backup option, and provide the database user account credentials using the --user and --password options:

    Subsequent to the above example, the backup is now available in the designated --target-dir path.

    A raw full backup is not and must be prepared before it can be used for a restore. The backup can be prepared any time after the backup is created and before the backup is restored. However, MariaDB recommends preparing a backup immediately after taking the backup to ensure that the backup is consistent.

    The backup should be prepared with the same version of MariaDB Backup that was used to create the backup.

    To prepare the backup, execute mariadb-backup or mariadb-backup with the --prepare option:

    For best performance, the --use-memory option should be set to the server's innodb_buffer_pool_size value.

    Once a full backup has been prepared to be point-in-time consistent, MariaDB Backup is used to copy backup data to the MariaDB Enterprise Server data directory.

    To restore from a full backup:

    1. Stop the MariaDB Enterprise Server

    2. Empty the data directory

    3. Restore from the "full" directory using the --copy-back option:

    MariaDB Backup writes to the data directory as the current user, which can be changed using sudo. To confirm that restored files are properly owned by the user that runs MariaDB Enterprise Server, run a command like this (adapted for the correct user/group):

    Once this is done, start MariaDB Enterprise Server:

    When the Server starts, it works from the restored data directory.

    Full backups of large data-sets can be time-consuming and resource-intensive. MariaDB Backup supports the use of incremental backups to minimize this impact.

    While full backups are resource-intensive at time of backup, the resource burden around incremental backups occurs when preparing for restore. First, the full backup is prepared for restore, then each incremental backup is applied.

    When you perform an incremental backup, MariaDB Backup compares a previous full or incremental backup to what it finds on MariaDB Community Server. It then creates a new backup containing the incremental changes.

    Incremental backup is supported for InnoDB tables. Tables using other storage engines receive full backups even during incremental backup operations.

    To increment a full backup, use the --incremental-basedir option to indicate the path to the full backup and the --target-dir option to indicate where you want to write the incremental backup:

    In this example, MariaDB Backup reads the /data/backups/full directory, and MariaDB Enterprise Server then creates an incremental backup in the /data/backups/inc1 directory.

    An incremental backup must be applied to a prepared full backup before it can be used in a restore operation. If you have multiple full backups to choose from, pick the nearest full backup prior to the incremental backup that you want to restore. You may also want to back up your full-backup directory, as it are modified by the updates in the incremental data.

    If your full backup directory is not yet prepared, run this to make it consistent:

    Then, using the prepared full backup, apply the first incremental backup's data to the full backup in an incremental preparation step:

    Once the incremental backup has been applied to the full backup, the full backup directory contains the changes from the incremental backup (that is, the inc1/ directory). Feel free to remove inc1/ to save disk space.

    Once you have prepared the full backup directory with all the incremental changes you need (as described above), stop the MariaDB Community Server, Empty its data directory, and restore from the original full backup directory using the --copy-back option:

    MariaDB Backup writes files into the data directory using either the current user or root (in the case of a sudo operation), which may be different from the system user that runs the database. Run the following to recursively update the ownership of the restored files and directories:

    Then, start MariaDB Enterprise Server. When the Server starts, it works from the restored data directory.

    In a partial backup, MariaDB Backup copies a specified subset of tablespaces from the MariaDB Enterprise Server data directory. Partial backups are useful in establishing a higher frequency of backups on specific data, at the expense of increased recovery complexity. In selecting tablespaces for a partial backup, please consider referential integrity.

    Command-line options can be used to narrow the set of databases or tables to be included within a backup:

    Option
    Description

    For example, you may wish to produce a partial backup, which excludes a specific database:

    Partial backups can also be incremental:

    As with full and incremental backups, partial backups are not point-in-time consistent. A partial backup must be prepared before it can be used for recovery.

    A partial restore can be performed from a full backup or partial backup.

    The preparation step for either partial or full backup restoration requires the use of transportable tablespaces for InnoDB. As such, each prepare operation requires the --export option:

    When using a partial incremental backup for restore, the incremental data must be applied to its prior partial backup data before its data is complete. If performing partial incremental backups, run the prepare statement again to apply the incremental changes onto the partial backup that served as the base.

    Unlike full and incremental backups, you cannot restore partial backups directly using MariaDB Backup. Further, as a partial backup does not contain a complete data directory, you cannot restore MariaDB Community Server to a startable state solely with a partial backup.

    To restore from a partial backup, you need to prepare a table on the MariaDB Community Server, then manually copy the files into the data directory.

    The details of the restore procedure depend on the characteristics of the table:

    As partial restores are performed while the server is running, not stopped, care should be taken to prevent production workloads during restore activity.

    Note: You can also use data from a full backup in a partial restore operation if you have prepared the data using the --export option as described above.

    To restore a non-partitioned table from a backup, first create a new table on MariaDB Community Server to receive the restored data. It should match the specifications of the table you're restoring.

    Be extra careful if the backup data is from a server with a different version than the restore server, as some differences (such as a differing ROW_FORMAT) can cause an unexpected result.

    1. Create an empty table for the data being restored:

    1. Modify the table to discard the tablespace:

    1. You can copy (or move) the files for the table from the backup to the data directory:

    1. Use a wildcard to include both the .ibd and .cfg files. Then, change the owner to the system user running MariaDB Community Server:

    1. Lastly, import the new tablespace:

    MariaDB Community Server looks in the data directory for the tablespace you copied in, then imports it for use. If the table is encrypted, it also looks for the encryption key with the relevant key ID that the table data specifies.

    1. Repeat this step for every table you wish to restore.

    Restoring a partitioned table from a backup requires a few extra steps compared to restoring a non-partitioned table.

    To restore a partitioned table from a backup, first create a new table on MariaDB Community Server to receive the restored data. It should match the specifications of the table you're restoring, including the partition specification.

    Be extra careful if the backup data is from a server with a different version than the restore server, as some differences (such as a differing ROW_FORMAT) can cause an unexpected result.

    1. Create an empty table for the data being restored:

    1. Then create a second empty table matching the column specification, but without partitions. This is your working table:

    1. For each partition you want to restore, discard the working table's tablespace:

    1. Then, copy the table files from the backup, using the new name:

    1. Change the owner to that of the user running MariaDB Community Server:

    1. Import the copied tablespace:

    1. Lastly, exchange the partition, copying the tablespace from the working table into the partition file for the target table:

    1. Repeat the above process for each partition until you have them all exchanged into the target table. Then delete the working table, as it's no longer necessary:

    This restores a partitioned table.

    When restoring a table with a full-text search (FTS) index, InnoDB may throw a schema mismatch error.

    In this case, to restore the table, it is recommended to:

    • Remove the corresponding .cfg file.

    • Restore data to a table without any secondary indexes including FTS.

    • Add the necessary secondary indexes to the restored table.

    For example, to restore table t1 with FTS index from database db1:

    1. In the MariaDB shell, drop the table you are going to restore:

    1. Create an empty table for the data being restored:

    1. Modify the table to discard the tablespace:

    1. In the operating system shell, copy the table files from the backup to the data directory of the corresponding database:

    1. Remove the .cfg file from the data directory:

    1. Change the owner of the newly copied files to the system user running MariaDB Community Server:

    1. In the MariaDB shell, import the copied tablespace:

    1. Verify that the data has been successfully restored:

    1. Add the necessary secondary indexes:

    1. The table is now fully restored:

    Point-in-time recovery (PITR) is .

    This page is: Copyright © 2025 MariaDB. All rights reserved.

    command on data that is to be used for a partial restore (when restoring only one or more selected tables) requires that you also use the
    --export
    option to create the necessary
    .cfg
    files to use in recovery.

    Run MariaDB Backup to restore the databases into that directory.

  • Change the ownership of all the restored files to the correct system user (e.g., chown -R mysql:mysql /var/lib/mysql).

  • Start MariaDB Enterprise Server, which now uses the restored data directory.

  • When ready, and if you have not already done so, delete the old data directory to free disk space.

  • In the above example, MariaDB Backup would run on the local system that runs MariaDB Enterprise Server. Where backups may be run against a remote server, the user authentication and authorization should be adjusted.

    While MariaDB Backup requires a user for backup operations, no user is required for restore operations since restores occur while MariaDB Enterprise Server is not running.

    --tables

    List of tables to include

    --tables-exclude

    List of tables to exclude

    --tables-file

    Path to file listing the tables to include

    --databases

    List of databases to include

    --databases-exclude

    List of databases to omit from the backup

    --databases-file

    Path to file listing the databases to include

    Nonblocking Backups

    Understanding Recovery

    Preparing Backups for Recovery

    Restore Requires Empty Data Directory

    Creating the Backup User

    Full Backup and Restore

    Performing Full Backups

    Preparing a Full Backup for Recovery

    Restoring from Full Backups

    Incremental Backup and Restore

    Performing Incremental Backups

    Preparing an Incremental Backup

    Restoring from Incremental Backups

    Partial Backup and Restore

    Performing a Partial Backup

    Preparing a Backup Before a Partial Restore

    Performing a Partial Restore

    Partial Restore Nonpartitioned Tables

    Partial Restore Partitioned Tables

    Partial Restore of Tables with Full-Text Indexes

    Point-in-Time Recoveries

    MariaDB ColumnStore Tools
    point-in-time consistent
    Partial Restore Non-partitioned Tables
    Partial Restore Partitioned Tables
    Partial Restore of Tables with Full-Text Indexes
    documented here
    spinner
    CREATE USER 'mariadb-backup'@'localhost'
    IDENTIFIED BY 'mbu_passwd';
    
    GRANT RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR
    ON *.*
    TO 'mariadb-backup'@'localhost';
    CREATE USER 'mariadb-backup'@'localhost'
    IDENTIFIED BY 'mbu_passwd';
    
    GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT
    ON *.*
    TO 'mariadb-backup'@'localhost';
    sudo mariadb-backup --backup \
          --target-dir=/data/backups/full \
          --user=mariadb-backup \
          --password=mbu_passwd
    sudo mariadb-backup --prepare \
       --use-memory=34359738368 \
       --target-dir=/data/backups/full
    mariadb-backup --copy-back --target-dir=/data/backups/full
    chown -R mysql:mysql /var/lib/mysql
    sudo systemctl start mariadb
    mariadb-backup --backup \
          --incremental-basedir=/data/backups/full \
          --target-dir=/data/backups/inc1 \
          --user=mariadb-backup \
          --password=mbu_passwd
    mariadb-backup --prepare --target-dir=/data/backups/full
    mariadb-backup --prepare \
          --target-dir=/data/backups/full \
          --incremental-dir=/data/backups/inc1
    mariadb-backup --copy-back --target-dir=/data/backups/full
    chown -R mysql:mysql /var/lib/mysql
    mariadb-backup --backup \
          --target-dir=/data/backups/part \
          --user=mariadb-backup \
          --password=mbu_passwd \
          --database-exclude=test
    mariadb-backup --backup \
          --incremental-basedir=/data/backups/part \
          --target-dir=/data/backups/part_inc1 \
          --user=mariadb-backup \
          --password=mbu_passwd  \
          --database-exclude=test
    mariadb-backup --prepare --export --target-dir=/data/backups/part
    mariadb-backup --prepare --export \
          --target-dir=/data/backups/part \
          --incremental-dir=/data/backups/part_inc1
    CREATE TABLE test.address_book (
       id INT PRIMARY KEY AUTO_INCREMENT,
       name VARCHAR(255),
       email VARCHAR(255));
    ALTER TABLE test.address_book DISCARD TABLESPACE;
    # cp /data/backups/part_inc1/test/address_book.* /var/lib/mysql/test
    # chown mysql:mysql /var/lib/mysql/test/address_book.*
    ALTER TABLE test.address_book IMPORT TABLESPACE;
    CREATE TABLE test.students (
       id INT PRIMARY KEY AUTO_INCREMENT
       name VARCHAR(255),
       email VARCHAR(255),
       graduating_year YEAR)
    PARTITION BY RANGE (graduating_year) (
       PARTITION p9 VALUES LESS THAN 2019
       PARTITION p1 VALUES LESS THAN MAXVALUE
    );
    CREATE TABLE test.students_work AS
    SELECT * FROM test.students WHERE NULL;
    ALTER TABLE test.students_work DISCARD TABLESPACE;
    # cp /data/backups/part_inc1/test/students.ibd /var/lib/mysql/test/students_work.ibd
    # cp /data/backups/part_inc1/test/students.cfg /var/lib/mysql/test/students_work.cfg
    # chown mysql:mysql /var/lib/mysql/test/students_work.*
    ALTER TABLE test.students_work IMPORT TABLESPACE;
    ALTER TABLE test.students EXCHANGE PARTITION p0 WITH TABLE test.students_work;
    DROP TABLE test.students_work;
    DROP TABLE IF EXISTS db1.t1;
    CREATE TABLE db1.t1(f1 CHAR(10)) ENGINE=INNODB;
    ALTER TABLE db1.t1 DISCARD TABLESPACE;
    $ sudo cp /data/backups/part/db1/t1.* /var/lib/mysql/db1
    $ sudo rm /var/lib/mysql/db1/t1.cfg
    $ sudo chown mysql:mysql /var/lib/mysql/db1/t1.*
    ALTER TABLE db1.t1 IMPORT TABLESPACE;
    SELECT * FROM db1.t1;
    +--------+
    | f1     |
    +--------+
    | ABC123 |
    +--------+
    ALTER TABLE db1.t1 FORCE, ADD FULLTEXT INDEX f_idx(f1);
    SHOW CREATE TABLE db1.t1\G
    *************************** 1. row ***************************
           Table: t1
    Create Table: CREATE TABLE `t1` (
      `f1` char(10) DEFAULT NULL,
      FULLTEXT KEY `f_idx` (`f1`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

    mariadb-backup Overview

    Complete MariaDB backup and recovery guide. Complete resource for backup methods, mariadb-backup usage, scheduling, and restoration for production use.

    mariadb-backup is an open source tool provided by MariaDB for performing physical online backups of InnoDB, Aria and MyISAM tables. For InnoDB, “hot online” backups are possible. It was originally forked from Percona XtraBackup 2.3.8. It is available on Linux and Windows.

    This tool provides a production-quality, nearly non-blocking method for performing full backups on running systems. While partial backups with mariadb-backup are technically possible, they require many steps and cannot be restored directly onto existing servers containing other data.

    mariadb-backup supports all of the main features of Percona XtraBackup 2.3.8, plus:

    • Backup/Restore of tables using Data-at-Rest Encryption.

    MariaDB authentication from MariaDB 10.4

    Backup/Restore of tables using InnoDB Page Compression.

  • with Galera Cluster.

  • Microsoft Windows support.

  • Backup/Restore of tables using the MyRocks storage engine. See Files Backed up by mariadb-backup: MyRocks Data Files for more information.

  • MariaDB Backup supports some additional features, such as:

    • Minimizes locks during the backup to permit more concurrency and to enable faster backups.

      • This relies on the usage of BACKUP STAGE commands and DDL logging.

      • This includes no locking during the copy phase of ALTER TABLE statements, which tends to be the longest phase of these statements.

    • Provides optimal backup support for all storage engines that store things on local disk.

    MariaDB Backup does not support some additional features.

    mariadb-backup supports various type of backups (and restores from those backups), documented on separate pages:

    • Full backup and restore

    • Incremental backup and restore

    • Partial backup and restore

    • Restoring individual databases, tables, and partitions

    The mariadb-backup executable is included in binary tarballs on Linux.

    mariadb-backup can also be installed via a package manager on Linux. Many Linux distributions provide MariaDB software "out of the box", including mariadb-backup. If your Linux distribution doesn't, however, you can install using a MariaDB repository.

    In order to do so, your system needs to be configured to install from one of the MariaDB repositories.

    You can configure your package manager to install it from MariaDB Corporation's MariaDB Package Repository by using the MariaDB Package Repository setup script.

    You can also configure your package manager to install it from MariaDB Foundation's MariaDB Repository by using the MariaDB Repository Configuration Tool.

    Installing with yum/dnf

    On RHEL, CentOS, Fedora, and other similar Linux distributions, it is highly recommended to install the relevant RPM package from MariaDB's repository using yum or dnf. Starting with RHEL 8 and Fedora 22, yum has been replaced by dnf, which is the next major version of yum. However, yum commands still work on many systems that use dnf. For example:

    Installing with apt-get

    On Debian, Ubuntu, and other similar Linux distributions, it is highly recommended to install the relevant DEB package from MariaDB's repository using apt-get. For example:

    Installing with zypper

    On SLES, OpenSUSE, and other similar Linux distributions, it is highly recommended to install the relevant RPM package from MariaDB's repository using zypper. For example:

    The mariadb-backup executable is included in MSI and ZIP packages on Windows.

    When using the Windows MSI installer, mariadb-backup can be installed by selecting Backup utilities:

    MariaDB MSI Installer showing the Backup utilities install option

    The command to use mariadb-backup and the general syntax is:

    For in-depth explanations on how to use mariadb-backup, see:

    • Full Backup and Restore with mariadb-backup

    • Incremental Backup and Restore with mariadb-backup

    • Partial Backup and Restore with mariadb-backup

    • Restoring Individual Tables and Partitions with mariadb-backup

    Options supported by mariadb-backup can be found on the mariadb-backup Options page.

    In addition to reading options from the command-line, mariadb-backup can also read options from option files.

    The following options relate to how MariaDB command-line tools handles option files. They must be given as the first argument on the command-line:

    Option
    Description

    --print-defaults

    Print the program argument list and exit.

    --no-defaults

    Don't read default options from any option file.

    --defaults-file=#

    Only read default options from the given option file.

    mariadb-backup reads server options from the following option groups from option files:

    Group
    Description

    [mariadb-backup]

    Options read by mariadb-backup.

    [mariadb-backup]

    Options read by mariadb-backup.

    [xtrabackup]

    Options read by mariadb-backup and Percona XtraBackup.

    mariadb-backup reads client options from the following option groups from option files:

    Group
    Description

    [mariadb-backup]

    Options read by mariadb-backup. Available starting with and .

    [mariadb-backup]

    Options read by mariadb-backup. Available starting with and

    [xtrabackup]

    Options read by mariadb-backup and Percona XtraBackup.

    mariadb-backup can optionally track your backup operations in a database table. This provides a centralized audit log and allows you to automate incremental backups by referencing the logical name of the previous backup instead of managing file paths.

    Table Location and Schema Changes (MariaDB 10.11):

    • MariaDB 10.11 and later: The history table is mysql.mariadb_backup_history and uses the InnoDB storage engine (transactional).

    • MariaDB 10.10 and earlier: The history table is PERCONA_SCHEMA.xtrabackup_history and uses the CSV storage engine.

    mariadb-backup needs to authenticate with the database server when it performs a backup operation (i.e. when the --backup option is specified). For most use cases, the user account that performs the backup needs to have the following global privileges on the database server.

    The required privileges are:

    CREATE USER 'mariadb-backup'@'localhost' IDENTIFIED BY 'mypassword';
    GRANT RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR ON *.* TO 'mariadb-backup'@'localhost';

    The required privileges are:

    CREATE USER 'mariadb-backup'@'localhost' IDENTIFIED BY 'mypassword';
    GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'mariadb-backup'@'localhost';

    If your database server is also using the MyRocks storage engine, then the user account that performs the backup will also need the SUPER global privilege. This is because mariadb-backup creates a checkpoint of this data by setting the rocksdb_create_checkpoint system variable, which requires this privilege. See MDEV-20577 for more information.

    CONNECTION ADMIN is also required where --kill-long-queries-timeout is greater than 0, and --no-lock isn't applied in order to KILL queries.

    REPLICA MONITOR (or alias SLAVE MONITOR) is also required where --galera-info or --slave-info is specified.

    To use the --history option(or the incremental history options), the backup user requires specific privileges on the history table.

    The user needs INSERT to create history records and SELECT to read them for incremental backups:

    GRANT SELECT, INSERT, CREATE, ALTER ON mysql.mariadb_backup_history TO 'mariadb-backup'@'localhost';

    The user needs privileges on the legacy PERCONA_SCHEMA:

    GRANT SELECT, INSERT, CREATE, ALTER ON PERCONA_SCHEMA.xtrabackup_history TO 'mariadb-backup'@'localhost';

    For Upgrading to 10.11 (One-Time Migration)

    If upgrading from an older version, mariadb-backup will attempt to migrate the old table to the new location on the first run. The backup user needs privileges to move and modify the old table:

    Alternatively, you can perform this migration manually before running the backup:

    The user account information can be specified with the --user and --password command-line options. For example:

    The user account information can also be specified in a supported client option group in an option file. For example:

    mariadb-backup does not need to authenticate with the database server when preparing or restoring a backup.

    mariadb-backup has to read MariaDB's files from the file system. Therefore, when you run mariadb-backup as a specific operating system user, you should ensure that user account has sufficient permissions to read those files.

    If you are using Linux and if you installed MariaDB with a package manager, then MariaDB's files will probably be owned by the mysql user and the mysql group.

    mariadb-backup supports Data-at-Rest Encryption.

    mariadb-backup will query the server to determine which key management and encryption plugin is being used, and then it will load that plugin itself, which means that mariadb-backup needs to be able to load the key management and encryption plugin's shared library.

    mariadb-backup will also query the server to determine which encryption keys it needs to use.

    In other words, mariadb-backup is able to figure out a lot of encryption-related information on its own, so normally one doesn't need to provide any extra options to backup or restore encrypted tables.

    mariadb-backup backs up encrypted and unencrypted tables as they are on the original server. If a table is encrypted, then the table will remain encrypted in the backup. Similarly, if a table is unencrypted, then the table will remain unencrypted in the backup.

    The primary reason that mariadb-backup needs to be able to encrypt and decrypt data is that it needs to apply InnoDB redo log records to make the data consistent when the backup is prepared. As a consequence, mariadb-backup does not perform many encryption or decryption operations when the backup is initially taken. MariaDB performs more encryption and decryption operations when the backup is prepared. This means that some encryption-related problems (such as using the wrong encryption keys) may not become apparent until the backup is prepared.

    The mariadb-backup SST method uses the mariadb-backup utility for performing SSTs. See for more information.

    mariadb-backup backs up many different files in order to perform its backup operation. See Files Backed up by mariadb-backup for a list of these files.

    mariadb-backup creates several different types of files during the backup and prepare phases. See Files Created by mariadb-backup for a list of these files.

    mariadb-backup can store the binary log position in the backup. See --binlog-info. This can be used for point-in-time recovery and to use the backup to setup a slave with the correct binlog position.

    mariadb-backup defaults to the server's default datadir value. See MDEV-12956 for more information.

    If mariadb-backup uses more file descriptors than the system is configured to allow, then users can see errors like the following:

    mariadb-backup throws an error and aborts when this error is encountered. See MDEV-19060 for more information.

    When this error is encountered, one solution is to explicitly specify a value for the --open-files-limit option either on the command line or in one of the supported server option group s in an option file. For example:

    An alternative solution is to set the soft and hard limits for the user account that runs mariadb-backup by adding new limits to /etc/security/limits.conf. For example, if mariadb-backup is run by the mysql user, then you could add lines like the following:

    After the system is rebooted, the above configuration should set new open file limits for the mysql user, and the user's ulimit output should look like the following:

    • mariadb-dump/mysqldump

    • How to backup with MariaDB (video)

    • MariaDB point-in-time recovery (video)

    • mariadb-backup and Restic (video)

    This page is licensed: CC BY-SA / Gnu FDL

    mariadb-backup was previously called mariabackup.

    Supported Features

    sudo yum install MariaDB-backup
    sudo apt-get install mariadb-backup
    sudo zypper install MariaDB-backup
    mariadb-backup <options>
    GRANT DROP, ALTER, RENAME ON PERCONA_SCHEMA.xtrabackup_history TO 'mariadb-backup'@'localhost';
    GRANT CREATE ON PERCONA_SCHEMA TO 'mariadb-backup'@'localhost';
    RENAME TABLE PERCONA_SCHEMA.xtrabackup_history TO mysql.mariadb_backup_history;
    ALTER TABLE mysql.mariadb_backup_history ENGINE=InnoDB;
    mariadb-backup --backup \
       --target-dir=/var/mariadb/backup/ \
       --user=mariadb-backup --password=mypassword
    [mariadb-backup]
    user=mariadb-backup
    password=mypassword
    2019-02-12 09:48:38 7ffff7fdb820  InnoDB: Operating system error number 23 in a file operation.
    InnoDB: Error number 23 means 'Too many open files in system'.
    InnoDB: Some operating system error numbers are described at
    InnoDB: http://dev.mysql.com/doc/refman/5.6/en/operating-system-error-codes.html
    InnoDB: Error: could not open single-table tablespace file ./db1/tab1.ibd
    InnoDB: We do not continue the crash recovery, because the table may become
    InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it.
    InnoDB: To fix the problem and start mysqld:
    InnoDB: 1) If there is a permission problem in the file and mysqld cannot
    InnoDB: open the file, you should modify the permissions.
    InnoDB: 2) If the table is not needed, or you can restore it from a backup,
    InnoDB: then you can remove the .ibd file, and InnoDB will do a normal
    InnoDB: crash recovery and ignore that table.
    InnoDB: 3) If the file system or the disk is broken, and you cannot remove
    InnoDB: the .ibd file, you can set innodb_force_recovery > 0 in my.cnf
    InnoDB: and force InnoDB to continue crash recovery here.
    [mariadb-backup]
    open_files_limit=65535
    mysql soft nofile 65535
    mysql hard nofile 65535
    ulimit -Sn
    65535
    ulimit -Hn
    65535

    Supported Features in MariaDB Enterprise Backup

    Backup Types

    Installing mariadb-backup

    Installing on Linux

    Installing with a Package Manager

    Installing on Windows

    Usage

    Options

    mariadb-backup will currently silently ignore unknown command-line options, so be extra careful about accidentally including typos in options or accidentally using options from later mariadb-backup versions. The reason for this is that mariadb-backup currently treats command-line options and options from equivalently. When it reads from these , it has to read a lot of options from the server option groups read by . However, mariadb-backup does not know about many of the options that it normally reads in these option groups. If mariadb-backup raised an error or warning when it encountered an unknown option, then this process would generate a large amount of log messages under normal use. Therefore, mariadb-backup

    Option Files

    Server Option Groups

    Client Option Groups

    Backup History Table

    On the first run after upgrading to MariaDB 10.11, mariadb-backup will attempt to migrate the old CSV table to the new InnoDB table. This requires specific privileges (see below).

    Authentication and Privileges

    File System Permissions

    Using mariadb-backup with Data-at-Rest Encryption

    Using mariadb-backup for Galera SSTs

    Files Backed up by mariadb-backup

    Files Created by mariadb-backup

    Binary Logs

    Known Issues

    No Default Data Directory

    Too Many Open Files

    See Also

    spinner
    is designed to silently ignore the unknown options instead. See
    about that.

    --defaults-extra-file=#

    Read this file after the global files are read.

    --defaults-group-suffix=#

    In addition to the default option groups, also read option groups with this suffix.

    [server]

    Options read by MariaDB Server.

    [mysqld]

    Options read by mariadbd, which includes both MariaDB Server and MySQL Server (where it is called mysqld).

    [mysqld-X.Y]

    Options read by a specific version of mysqld, which includes both MariaDB Server and MySQL Server. For example: [mysqld-10.6].

    [mariadb]

    Options read by MariaDB Server.

    [mariadb-X.Y]

    Options read by a specific version of MariaDB Server. For example: [mariadb-10.6].

    [mariadbd]

    Options read by MariaDB Server. Available from MariaDB 10.5.4.

    [mariadbd-X.Y]

    Options read by a specific version of MariaDB Server. For example: [mariadbd-10.6]. Available from MariaDB 10.5.4.

    [client-server]

    Options read by all MariaDB client programs and the MariaDB Server. This is useful for options like socket and port, which is common between the server and the clients.

    [galera]

    Options read by MariaDB Server, but only if it is compiled with Galera Cluster support. All builds on Linux are compiled with Galera Cluster support. When using one of these builds, options from this option group are read even if the Galera Cluster functionality is not enabled.

    [client]

    Options read by all MariaDB and MySQL client programs, which includes both MariaDB and MySQL clients. For example, mysqldump.

    [client-server]

    Options read by all MariaDB client programs and the MariaDB Server. This is useful for options like socket and port, which is common between the server and the clients. Available starting with , , and .

    [client-mariadb]

    Options read by all MariaDB client programs. Available starting with , , and .

    Point-in-time recovery (PITR)
    Setting up a Replica with mariadb-backup
    Using Encryption and Compression Tools With mariadb-backup
    option files
    option files
    mariadbd
    MDEV-18215

    Partitioning Overview

    Complete Partitioning Overview guide for MariaDB. Complete reference documentation for implementation, configuration, and usage for production use.

    In MariaDB, a table can be split in smaller subsets. Both data and indexes are partitioned.

    Uses for Partitioning

    There can be several reasons to use this feature:

    • If you often need to delete a large set of rows, such as all rows for a given year, using partitions can help, as dropping a partition with many rows is very fast, while deleting a lot of rows can be very slow.

    • Very large tables and indexes can be slow even with optimized queries. But if the target table is partitioned, queries that read a small number of partitions can be much faster. However, this means that the queries have to be written carefully in order to only access a given set of partitions.

    • Partitioning allows one to distribute files over multiple storage devices. For example, we can have historical data on slower, larger disks (historical data are not supposed to be frequently read); and current data can be on faster disks, or SSD devices.

    • In case we separate historical data from recent data, we will probably need to take regular backups of one partition, not the whole table.

    When partitioning a table, the use should decide:

    • a partitioning type;

    • a partitioning expression.

    A partitioning type is the method used by MariaDB to decide how rows are distributed over existing partitions. Choosing the proper partitioning type is important to distribute rows over partitions in an efficient way.

    With some partitioning types, a partitioning expression is also required. A partitioning function is an SQL expression returning an integer or temporal value, used to determine which partition will contain a given row. The partitioning expression is used for all reads and writes on involving the partitioned table, thus it should be fast.

    MariaDB supports the following partitioning types:

    By default, MariaDB permits partitioning. You can determine this by using the statement, for example:

    If partition is listed as DISABLED:

    MariaDB has either been built without partitioning support, or has been started with the option, or one of its variants:

    and you will not be able to create partitions.

    It is possible to create a new partitioned table using .

    allows one to:

    • Partition an existing table;

    • Remove partitions from a partitioned table (with all data in the partition);

    • Add/remove partitions, or reorganize them, as long as the partitioning function allows these operations (see below);

    can be used to add partitions to an existing table:

    With partitions, it is only possible to add a partition to the high end of the range, not the low end. For example, the following results in an error:

    You can work around this by using REORGANIZE PARTITION to split the partition instead. See .

    is used to reduce the number of HASH or KEY partitions by the specified number. For example, given the following table with 5 partitions:

    The following statement reduces the number of partitions by 2, leaving the table with 3 partitions:

    can be used to convert partitions in an existing table to a standalone table:

    CONVERT TABLE does the reverse, converting a table into a partition:

    When converting tables to a partition, validation is performed on each row to ensure it meets the partition requirements. This can be very slow in the case of larger tables. It is possible to disable this validation by specifying the WITHOUT VALIDATION option.

    WITH VALIDATION will result in the validation being performed, and is the default behaviour.

    An alternative to convert partitions to tables is to use . This requires having to manually do the following steps:

    1. Create an empty table with the same structure as the partition.

    2. Exchange the table with the partition.

    3. Drop the empty partition.

    For example:

    Similarly, to do the reverse and convert a table into a partition [ALTER TABLE](../../reference/sql-statements/data-definition/alter/alter-table/README.md) ... EXCHANGE PARTITION can also be used, with the following manual steps required:

    • create the partition

    • exchange the partition with the table

    • drop the old table:

    For example:

    can be used to drop specific partitions (and discard all data within the specified partitions) for and partitions. It cannot be used on or partitions. To rather remove all partitioning, while leaving the data unaffected, see .

    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2 allows to exchange a partition or subpartition with another table.

    The following requirements must be met:

    • Table t1 must be partitioned, and table t2 cannot be partitioned.

    • Table t2 cannot be a temporary table.

    • Table t1 and t2 must otherwise be identical.

    • Any existing row in t2 must match the conditions for storage in the exchanged partition p1 unless, from

    By default, MariaDB performs the validation to see that each row meets the partition requirements, and the statement fails if a row does not fit.

    This attempted exchange fails, as the value is already in t2, and 2015-05-05 is outside of the partition conditions:

    This validation is performed for each row, and can be very slow in the case of larger tables. It is possible to disable this validation by specifying the WITHOUT VALIDATION option:

    WITH VALIDATION results in the validation being performed, and is the default behavior.

    removes all partitioning from the table, while leaving the data unaffected. To rather drop a particular partition (and discard all of its data), see .

    Reorganizing partitions allows one to adjust existing partitions, without losing data. Specifically, the statement can be used for:

    • Splitting an existing partition into multiple partitions.

    • Merging a number of existing partitions into a new, single, partition.

    • Changing the ranges for a subset of existing partitions defined using VALUES LESS THAN.

    An existing partition can be split into multiple partitions. This can also be used to add a new partition at the low end of a partition (which is not possible by ).

    Similarly, if MAXVALUE binds the high end:

    A number of existing partitions can be merged into a new partition, for example:

    The statement can also be used for renaming partitions. Note that this creates a copy of the partition:

    [ALTER TABLE](../../reference/sql-statements/data-definition/alter/alter-table/README.md) ... TRUNCATE PARTITION

    removes all data from the specified partition/s, leaving the table and partition structure unchanged. Partitions don't need to be contiguous:

    Similar to , key distributions for specific partitions can also be analyzed and stored, for example:

    Similar to , specific partitions can be checked for errors, for example:

    The ALL keyword can be used in place of the list of partition names, and the check operation are performed on all partitions.

    Similar to , specific partitions can be repaired:

    As with , the QUICK and EXTENDED options are available. However, the USE_FRM option cannot be used with this statement on a partitioned table.

    REPAIR PARTITION fails if there are duplicate key errors. ALTER IGNORE TABLE ... REPAIR PARTITION can be used in this case.

    The ALL keyword can be used in place of the list of partition names, and the repair operation are performed on all partitions.

    Similar to , specific partitions can be checked for errors:

    OPTIMIZE PARTITION does not support per-partition optimization on InnoDB tables, and will issue a warning and cause the entire table to rebuilt and analyzed. ALTER TABLE ... REBUILD PARTITION and ALTER TABLE ... ANALYZE PARTITION can be used instead.

    The ALL keyword can be used in place of the list of partition names, and the optimize operation are performed on all partitions.

    Some MariaDB allow more interesting uses for partitioning.

    The storage engine allows one to:

    • Treat a set of identical defined tables as one.

    • A MyISAM table can be in many different MERGE sets and also used separately.

    allows one to:

    • Move partitions of the same table on different servers. In this way, the workload can be distributed on more physical or virtual machines (data sharding).

    • All partitions of a SPIDER table can also live on the same machine. In this case there are a small overhead (SPIDER uses connections to localhost), but queries that read multiple partitions will use parallel threads.

    allows one to:

    • Build a table whose partitions are tables using different storage engines (like InnoDB, MyISAM, or even engines that do not support partitioning).

    • Build an indexable, writeable table on several data files. These files can be in different formats.

    See also:

    • contains information about existing partitions.

    • for suggestions on using partitions

    This page is licensed: CC BY-SA / Gnu FDL

  • Exchange a partition with a table;
  • Perform administrative operations on some or all partitions (analyze, optimize, check, repair).

  • , the WITHOUT VALIDATION option is specified.
    Changing the value lists for a subset of partitions defined using VALUES I.
  • Renaming partitions.

  • SHOW PLUGINS;
    ...
    | Aria                          | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
    | FEEDBACK                      | DISABLED | INFORMATION SCHEMA | NULL    | GPL     |
    | partition                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
    +-------------------------------+----------+--------------------+---------+---------+
    | partition                     | DISABLED | STORAGE ENGINE     | NULL    | GPL     |
    +-------------------------------+----------+--------------------+---------+---------+
    --skip-partition
    --disable-partition
    --partition=OFF
    ADD PARTITION [IF NOT EXISTS] (partition_definition)
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 ADD PARTITION (
      PARTITION p4 VALUES LESS THAN (2017), 
      PARTITION p5 VALUES LESS THAN (2018)
    );
    ALTER TABLE t1 ADD PARTITION (
      PARTITION p0a VALUES LESS THAN (2012)
    );
    ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition
    COALESCE PARTITION number
    CREATE OR REPLACE TABLE t1 (v1 INT)
      PARTITION BY KEY (v1)
      PARTITIONS 5;
    ALTER TABLE t1 COALESCE PARTITION 2;
    CONVERT PARTITION partition_name TO TABLE tbl_name
    CONVERT TABLE normal_table TO partition_definition
    CREATE OR REPLACE TABLE t1 (
       dt DATETIME NOT NULL
     )
       ENGINE = InnoDB
       PARTITION BY RANGE (YEAR(dt))
       (
       PARTITION p0 VALUES LESS THAN (2013),
       PARTITION p1 VALUES LESS THAN (2014),
       PARTITION p2 VALUES LESS THAN (2015),
       PARTITION p3 VALUES LESS THAN (2016)
     );
    
    INSERT INTO t1 VALUES ('2013-11-11'),('2014-11-11'),('2015-11-11');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 CONVERT PARTITION p3 TO TABLE t2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB)
    
    SHOW CREATE TABLE t2\G
    *************************** 1. row ***************************
           TABLE: t2
    CREATE TABLE: CREATE TABLE `t2` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
    ALTER TABLE t1 CONVERT TABLE t2 TO PARTITION p3 VALUES LESS THAN (2016);
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    3 rows in set (0.001 sec)
    
    SELECT * FROM t2;
    ERROR 1146 (42S02): Table 'test.t2' doesn't exist
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB,
     PARTITION `p3` VALUES LESS THAN (2016) ENGINE = InnoDB)
    CONVERT TABLE normal_table TO partition_definition [{WITH | WITHOUT} VALIDATION]
    CREATE OR REPLACE TABLE t1 (
       dt DATETIME NOT NULL
     )
       ENGINE = InnoDB
       PARTITION BY RANGE (YEAR(dt))
       (
       PARTITION p0 VALUES LESS THAN (2013),
       PARTITION p1 VALUES LESS THAN (2014),
       PARTITION p2 VALUES LESS THAN (2015),
       PARTITION p3 VALUES LESS THAN (2016)
     );
    
    INSERT INTO t1 VALUES ('2013-11-11'),('2014-11-11'),('2015-11-11');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    CREATE OR REPLACE TABLE t2 LIKE t1;
    
    ALTER TABLE t2 REMOVE PARTITIONING;
    
    ALTER TABLE t1 EXCHANGE PARTITION p3 WITH TABLE t2;
    
    ALTER TABLE t1 DROP PARTITION p3;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB)
    
    SHOW CREATE TABLE t2\G
    *************************** 1. row ***************************
           TABLE: t2
    CREATE TABLE: CREATE TABLE `t2` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
    ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2016));
    
    ALTER TABLE t1 EXCHANGE PARTITION p3 WITH TABLE t2;
    
    DROP TABLE t2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB,
     PARTITION `p3` VALUES LESS THAN (2016) ENGINE = InnoDB)
    DROP PARTITION [IF EXISTS] partition_names
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    INSERT INTO t1 VALUES ('2012-11-15');
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-11-15 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 DROP PARTITION p0;
    
    SELECT * FROM t1;
    Empty set (0.002 sec)
    EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH | WITHOUT} VALIDATION]
    EXCHANGE PARTITION partition_name WITH TABLE tbl_name
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014)
    );
    
    CREATE OR REPLACE TABLE t2 (
      dt DATETIME NOT NULL
    ) ENGINE = InnoDB;
    
    INSERT INTO t1 VALUES ('2012-01-01'),('2013-01-01');
    
    INSERT INTO t2 VALUES ('2013-02-02');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-01-01 00:00:00 |
    | 2013-01-01 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2013-02-02 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-01-01 00:00:00 |
    | 2013-02-02 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2013-01-01 00:00:00 |
    +---------------------+
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014)
    );
    
    CREATE OR REPLACE TABLE t2 (
      dt DATETIME NOT NULL
    ) ENGINE = InnoDB;
    
    INSERT INTO t1 VALUES ('2012-02-02'),('2013-03-03');
    
    INSERT INTO t2 VALUES ('2015-05-05');
    
    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2;
    ERROR 1526 (HY000): Table has no partition for value 0
    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2 WITHOUT VALIDATION;
    Query OK, 0 rows affected (0.048 sec)
    REMOVE PARTITIONING
    ALTER TABLE t1 REMOVE PARTITIONING;
    REORGANIZE PARTITION [partition_names INTO (partition_definitions)]
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p0 INTO (
        PARTITION p0a VALUES LESS THAN (2012),
        PARTITION p0b VALUES LESS THAN (2013)
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016),
      PARTITION p4 VALUES LESS THAN MAXVALUE
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p4 INTO (
        PARTITION p4 VALUES LESS THAN (2017),
        PARTITION p5 VALUES LESS THAN MAXVALUE
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p2,p3 INTO (
        PARTITION p2 VALUES LESS THAN (2016)
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p3 INTO (
      PARTITION p3 VALUES LESS THAN (2017)
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p3 INTO (
      PARTITION p3_new VALUES LESS THAN (2016)
    );
    TRUNCATE PARTITION partition_names
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    INSERT INTO t1 VALUES ('2012-11-01'),('2013-11-02'),('2014-11-03'),('2015-11-04');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-11-01 00:00:00 |
    | 2013-11-02 00:00:00 |
    | 2014-11-03 00:00:00 |
    | 2015-11-04 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 TRUNCATE PARTITION p0,p2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-02 00:00:00 |
    | 2015-11-04 00:00:00 |
    +---------------------+
    ALTER TABLE t1 ANALYZE PARTITION p0,p1,p3;
    +---------+---------+----------+----------+
    | Table   | Op      | Msg_type | Msg_text |
    +---------+---------+----------+----------+
    | test.t1 | analyze | status   | OK       |
    +---------+---------+----------+----------+
    CHECK PARTITION {ALL | PARTITION [,partition2 ...]}
    ALTER TABLE t1 CHECK PARTITION p1,p3;
    +---------+-------+----------+----------+
    | Table   | Op    | Msg_type | Msg_text |
    +---------+-------+----------+----------+
    | test.t1 | check | status   | OK       |
    +---------+-------+----------+----------+
    REPAIR PARTITION {ALL | partition [,partition2 ...]} [QUICK] [EXTENDED]
    ALTER TABLE t1 REPAIR PARTITION p0,p3;
    +---------+--------+----------+----------+
    | Table   | Op     | Msg_type | Msg_text |
    +---------+--------+----------+----------+
    | test.t1 | repair | status   | OK       |
    +---------+--------+----------+----------+
    OPTIMIZE PARTITION {ALL | PARTITION [,partition2 ...]}
    ALTER TABLE t1 OPTIMIZE PARTITION p0,p3;
    +---------+----------+----------+----------+
    | Table   | Op       | Msg_type | Msg_text |
    +---------+----------+----------+----------+
    | test.t1 | optimize | status   | OK       |
    +---------+----------+----------+----------+

    Partitioning Types

    Enabling Partitioning

    Using Partitions

    Adding Partitions

    Coalescing Partitions

    Converting Partitions to/from Tables

    This feature is available from MariaDB 10.7.

    CONVERT TABLE ... WITH / WITHOUT VALIDATION

    This feature is available from MariaDB 11.4.

    Dropping Partitions

    Exchanging Partitions

    WITH / WITHOUT VALIDATION

    This feature is available from MariaDB 11.4.

    Removing Partitioning

    Reorganizing Partitions

    Splitting Partitions

    Merging Partitions

    Changing Ranges

    Renaming Partitions

    Truncating Partitions

    Analyzing Partitions

    Checking Partitions

    Repairing Partitions

    Optimizing Partitions

    Partitioning for Specific Storage Engines

    See Also

    RANGE
    LIST
    RANGE COLUMNS and LIST COLUMNS
    HASH
    SHOW PLUGINS
    --skip-partition
    CREATE TABLE
    ALTER TABLE
    ADD PARTITION
    RANGE
    Splitting Partitions
    ALTER TABLE
    ALTER TABLE
    ALTER TABLE EXCHANGE PARTITION
    ALTER TABLE DROP PARTITION
    RANGE
    LIST
    HASH
    KEY
    Removing Partitioning
    ALTER TABLE REMOVE PARTITIONING
    Dropping Partitions
    RANGE
    Adding Partitions
    ALTER TABLE REORGANIZE PARTITION
    ALTER TABLE TRUNCATE PARTITION
    ANALYZE TABLE
    CHECK TABLE
    REPAIR TABLE
    REPAIR TABLE
    OPTIMIZE TABLE
    storage engines
    MERGE
    MyISAM
    SPIDER
    CONNECT
    Using CONNECT - Partitioning and Sharding
    ALTER TABLE
    INFORMATION_SCHEMA.PARTITIONS
    Partition Maintenance
    spinner
    LINEAR HASH
    KEY
    LINEAR KEY
    SYSTEM_TIME
    mariadb-backup SST Method
    Manual SST of Galera Cluster Node With mariadb-backup
    Configuring MariaDB Replication between MariaDB Galera Cluster and MariaDB Server
    Configuring MariaDB Replication between Two MariaDB Galera Clusters
    wsrep_local_state_uuid
    wsrep_last_committed
    wsrep_local_state_uuid
    wsrep_last_committed
    Galera
    mariadb-backup SST method
    mariadb-backup SST method
    2016 Google Summer of Code
    report the bug

    mariadb-backup Options

    Reference for mariadb-backup (mariabackup) command-line options. Covers --backup, --prepare, --copy-back, --move-back, streaming, and incremental backups.

    mariadb-backup was previously called mariabackup.

    mariadb-backup Options (mariabackup)

    Use this page as a reference for mariadb-backup / mariabackup command-line options. It focuses on the options (flags) you use for physical (file-based) MariaDB backups, including hot online backups for InnoDB.

    Quick Reference (Most Searched Options)

    • Take a physical backup: --backup + --target-dir

    • Prepare a backup: (or legacy )

    • Restore a backup: or

    • Incremental backups: +

    • Replication/Galera metadata: , ,

    • Stream output (pipes to gzip/gpg/etc): +

    Full backup (physical):

    Prepare (make files consistent for restore):

    Restore:

    Incremental backup (delta against an existing base backup):

    Prepares an existing backup to restore to the MariaDB Server. This is only valid in innobackupex mode, which can be enabled with the option.

    Files that mariadb-backup generates during operations in the target directory are not ready for use on the Server. Before you can restore the data to MariaDB, you first need to prepare the backup.

    In the case of full backups, the files are not point in time consistent, since they were taken at different times. If you try to restore the database without first preparing the data, InnoDB rejects the new data as corrupt. Running mariadb-backup with the command readies the data so you can restore it to MariaDB Server. When working with incremental backups, you need to use the --prepare command and the option to update the base backup with the deltas from an incremental backup.

    Once the backup is ready, you can use the or the commands to restore the backup to the server.

    If this option is used when preparing a backup, then only the redo log apply stage are performed, and other stages of crash recovery are ignored. This option is used with incremental backups.

    Backs up your databases.

    Using this command option, mariadb-backup performs a backup operation on your database or databases. The backups are written to the target directory, as set by the option.

    mariadb-backup can perform full and incremental backups. A full backup creates a snapshot of the database in the target directory. An incremental backup checks the database against a previously taken full backup, (defined by the option) and creates delta files for these changes.

    In order to restore from a backup, you first need to run mariadb-backup with the --prepare option, to make a full backup point-in-time consistent or to apply incremental backup deltas to base. Then you can run mariadb-backup again with either the or commands to restore the database.

    For more information, see and .

    Defines how mariadb-backup retrieves the binary log coordinates from the server.

    The --binlog-info option supports the following retrieval methods. When no retrieval method is provided, it defaults to AUTO.

    Option
    Description

    Using this option, you can control how mariadb-backup retrieves the server's binary log coordinates corresponding to the backup.

    When enabled, whether using ON or AUTO, mariadb-backup retrieves information from the binlog during the backup process. When disabled with OFF, mariadb-backup runs without attempting to retrieve binary log information. You may find this useful when you need to copy data without metadata like the binlog or replication coordinates.

    Currently, the LOCKLESS option depends on features unsupported by MariaDB Server. See the description of the file for more information. If you attempt to run mariadb-backup with this option, then it causes the utility to exit with an error.

    Defines whether you want to close file handles.

    Using this option, you can tell mariadb-backup that you want to close file handles. Without this option, mariadb-backup keeps files open in order to manage DDL operations. When working with particularly large tablespaces, closing the file can make the backup more manageable. However, it can also lead to inconsistent backups. Use at your own risk.

    Defines the compression algorithm for backup files.

    The --compress option only supports the now deprecated quicklz algorithm.

    Option
    Description

    If a backup is compressed using this option, then mariadb-backup will record that detail in the file.

    Defines the working buffer size for compression threads.

    mariadb-backup can perform compression operations on the backup files before writing them to disk. It can also use multiple threads for parallel data compression during this process. Using this option, you can set the chunk size each thread uses during compression. It defaults to 64K.

    To further configure backup compression, see the and options.

    Defines the number of threads to use in compression.

    mariadb-backup can perform compression operations on the backup files before writing them to disk. Using this option, you can define the number of threads you want to use for this operation. You may find this useful in speeding up the compression of particularly large databases. It defaults to single-threaded.

    To further configure backup compression, see the and options.

    Restores the backup to the data directory.

    Using this command, mariadb-backup copies the backup from the target directory to the data directory, as defined by the --datadir option. You must stop the MariaDB Server before running this command. The data directory must be empty. If you want to overwrite the data directory with the backup, use the --force-non-empty-directories option.

    Bear in mind, before you can restore a backup, you first need to run mariadb-backup with the --prepare option. In the case of full backups, this makes the files point-in-time consistent. With incremental backups, this applies the deltas to the base backup. Once the backup is prepared, you can run --copy-back to apply it to MariaDB Server.

    Running the --copy-back command copies the backup files to the data directory. Use this command if you want to save the backup for later. If you don't want to save the backup for later, use the --move-back option.

    Defines whether to write a core file.

    Using this option, you can configure mariadb-backup to dump its core to file in the event that it encounters fatal signals. You may find this useful for review and debugging purposes.

    Defines the databases and tables you want to back up.

    Using this option, you can define the specific database or databases you want to back up. In cases where you have a particularly large database or otherwise only want to back up a portion of it, you can optionally also define the tables on the database.

    In cases where you want to back up most databases on a server or tables on a database, but not all, you can set the specific databases or tables you don't want to back up using the --databases-exclude option.

    If a backup is a partial backup, then mariadb-backup will record that detail in the xtrabackup_info file.

    In innobackupex mode, which can be enabled with the --innobackupex option, the --databases option can be used as described above, or it can be used to refer to a file, just as the can in the normal mode.

    Defines the databases you don't want to back up.

    Using this option, you can define the specific database or databases you want to exclude from the backup process. You may find it useful when you want to back up most databases on the server or tables on a database, but would like to exclude a few from the process.

    To include databases in the backup, see the --databases option.

    If a backup is a partial backup, then mariadb-backup records that detail in the xtrabackup_info file.

    Defines the path to a file listing databases and/or tables you want to back up.

    Format the databases file to list one element per line, with the following syntax:

    In cases where you need to back up a number of databases or specific tables in a database, you may find the syntax for the --databases and --databases-exclude options a little cumbersome. Using this option you can set the path to a file listing the databases or databases and tables you want to back up.

    For instance, listing the databases and tables for a backup in a file called main-backup:

    If a backup is a partial backup, mariadb-backup records that detail in the xtrabackup_info file.

    Defines the path to the database root.

    Using this option, you can define the path to the source directory. This is the directory that mariadb-backup reads for the data it backs up. It should be the same as the MariaDB Server datadir system variable.

    This is a debug-only option used by the Xtrabackup test suite.

    Deprecated, for details see the --compress option.

    This option requires that you have the qpress utility installed on your system.

    Defines whether you want to decompress previously compressed backup files.

    When you run mariadb-backup with the --compress option, it compresses the subsequent backup files, using the QuickLZ algorithm. Using this option, mariadb-backup decompresses the compressed files from a previous backup.

    For instance, run a backup with compression:

    Then, decompress the backup:

    You can enable the decryption of multiple files at a time using the --parallel option. By default, mariadb-backup does not remove the compressed files from the target directory. To delete these files, use the --remove-original option.

    Defines the debug sync point. This option is only used by the mariadb-backup test suite.

    Defines the path to an extra default option file.

    Using this option, you can define an extra default option file for mariadb-backup. Unlike --defaults-file, this file is read after the default option files are read, allowing you to only overwrite the existing defaults.

    Defines the path to the default option file.

    Using this option, you can define a default option file for mariadb-backup. Unlike the --defaults-extra-file option, when this option is provided, it completely replaces all default option files.

    Defines the option group to read in the option file.

    In situations where you find yourself using certain mariadb-backup options consistently every time you call it, you can set the options in an option file. The --defaults-group option defines what option group mariadb-backup reads for its options.

    Options you define from the command-line can be set in the configuration file using minor formatting changes. For instance, if you find yourself perform compression operations frequently, you might set --compress-threads and --compress-chunk-size options in this way:

    Now whenever you run a backup with the --compress option, it always performs the compression using 12 threads and 64K chunks.

    See and for a list of the option groups read by mariadb-backup by default.

    When this option is used with --backup, if mariadb-backup encounters a page that has a non-zero key_version value, then mariadb-backup assumes that the page is encrypted.

    Use --skip-encrypted-backup instead to allow mariadb-backup to copy unencrypted tables that were originally created before MySQL 5.1.48.

    If this option is provided during the --prepare stage, then it tells mariadb-backup to create .cfg files for each InnoDB file-per-table tablespace. These .cfg files are used to import transportable tablespaces in the process of restoring partial backups and restoring individual tables and partitions.

    The --export option could require rolling back incomplete transactions that had modified the table. This will likely create a "new branch of history" that does not correspond to the server that had been backed up, which makes it impossible to apply another incremental backup on top of such additional changes. The option should only be applied when doing a --prepare of the last incremental.

    mariadb-backup did not support the --export option. See about that. In earlier versions of MariaDB, this means that mariadb-backup could not create .cfg files for InnoDB file-per-table tablespaces during the --prepare stage. You can still import file-per-table tablespaces without the .cfg files in many cases, so it may still be possible in those versions to restore partial backups or to restore individual tables and partitions with just the .ibd files. If you have a full backup and you need to create .cfg files for InnoDB file-per-table tablespaces, then you can do so by preparing the backup as usual without the --export option, and then restoring the backup, and then starting the server. At that point, you can use the server's built-in features to copy the transportable tablespaces.

    Saves an extra copy of the xtrabackup_checkpoints and xtrabackup_info files into the given directory.

    When using the --backup option, mariadb-backup produces a number of backup files in the target directory. Using this option, you can have mariadb-backup produce additional copies of the xtrabackup_checkpoints and xtrabackup_info files in the given directory.

    This is especially useful when using --stream for streaming output, e.g. for compression and/or encryption using external tools in combination with incremental backups, as the xtrabackup_checkpoints file necessary to determine the LSN to continue the incremental backup from is still accessible without uncompressing / decrypting the backup file first. Pass in the --extra-lsndir of the previous backup as --incremental-basedir .

    Allows --copy-back or --move-back options to use non-empty target directories.

    When using mariadb-backup with the --copy-back or --move-back options, they normally require a non-empty target directory to avoid conflicts. Using this option with either of command allows mariadb-backup to use a non-empty directory.

    Bear in mind that this option does not enable overwrites. When copying or moving files into the target directory, if mariadb-backup finds that the target file already exists, it fails with an error.

    Defines the type of query allowed to complete before mariadb-backup issues the global lock.

    The --ftwrl-wait-query-type option supports the following query types. The default value is ALL.

    Option
    Description

    When mariadb-backup runs, it issues a global lock to prevent data from changing during the backup process. When it encounters a statement in the process of executing, it waits until the statement is finished before issuing the global lock. Using this option, you can modify this default behavior to ensure that it waits only for certain query types, such as for SELECT and UPDATE statements.

    Defines the minimum threshold for identifying long-running queries for FTWRL.

    When mariadb-backup runs, it issues a global lock to prevent data from changing during the backup process and ensure a consistent record. If it encounters statements still in the process of executing, it waits until they complete before setting the lock. Using this option, you can set the threshold at which mariadb-backup engages FTWRL. When it --ftwrl-wait-timeout is not 0 and a statement has run for at least the amount of time given this argument, mariadb-backup waits until the statement completes or until the --ftwrl-wait-timeout expires before setting the global lock and starting the backup.

    Defines the timeout to wait for queries before trying to acquire the global lock. The global lock refers to BACKUP STAGE BLOCK_COMMIT. The global lock refers to FLUSH TABLES WITH READ LOCK (FTWRL).

    When mariadb-backup runs, it acquires a global lock to prevent data from changing during the backup process and ensure a consistent record. If it encounters statements still in the process of executing, it can be configured to wait until the statements complete before trying to acquire the global lock.

    If the --ftwrl-wait-timeout is set to 0, mariadb-backup tries to acquire the global lock immediately without waiting. This is the default value.

    If the --ftwrl-wait-timeout is set to a non-zero value, then mariadb-backup waits for the configured number of seconds until trying to acquire the global lock.

    mariadb-backup exits if it can't acquire the global lock after waiting for the configured number of seconds.

    The --ftwrl-wait-timeout option specifies the maximum time that mariadb-backup will wait to obtain the global lock required to begin a consistent backup.

    this lock is acquired with BACKUP STAGE BLOCK_COMMIT.

    this lock is acquired with FLUSH TABLES WITH READ LOCK (FTWRL).

    If the lock cannot be obtained within the configured timeout, the backup process fails.

    This option helps avoid failures caused by long-running MariaDB queries that block backup locks.

    Example Errors

    When the timeout is not set appropriately, backups may fail with messages such as:

    or

    Example log excerpt:

    Originally, mariadb-backup could wait indefinitely for the lock. Starting with the fix for MDEV-20230:

    • The --ftwrl-wait-timeout option also ensures mariadb backup exits gracefully if the lock cannot be obtained within the timeout period.

    • This prevents backups from hanging when lock acquisition is blocked by long-running queries.

    When to Use

    Use --ftwrl-wait-timeout when:

    • Your workload includes long-running queries (for example, ALTER TABLE or large INSERT batches).

    • Backups sometimes fail with lock wait timeout errors.

    • You want mariadb-backup to either wait longer for the lock or exit cleanly if it cannot be obtained.

    Defines whether you want to back up information about a Galera Cluster node's state.

    When this option is used, mariadb-backup creates an additional file called xtrabackup_galera_info, which records information about a Galera Cluster node's state. It records the values of the and status variables.

    You should only use this option when backing up a Galera Cluster node. If the server is not a Galera Cluster node, then this option has no effect.

    This option, when enabled and used with GTID replication, will rotate the binary logs at backup time.

    Defines whether you want to track backup history in the mysql.mariadb_backup_history table.

    When using this option, mariadb-backup records its operation in a table on the MariaDB Server. Passing a name to this option allows you group backups under arbitrary terms for later processing and analysis.

    Information is written to mysql.mariadb_backup_history.

    mariadb-backup also records this in the file.

    Defines the hostname for the MariaDB Server you want to back up.

    This option defines the hostname or IP address to use when connecting to a local MariaDB Server over TCP/IP. By default, mariadb-backup attempts to connect to localhost.

    This option is a regular expression to be matched against table names in databasename.tablename format. It is equivalent to the --tables option. This is only valid in innobackupex mode, which can be enabled with the --innobackupex option.

    Defines whether you want to take an increment backup, based on another backup. This is only valid in innobackupex mode, which can be enabled with the --innobackupex option.

    Using this option with the --backup option makes the operation incremental rather than a complete overwrite. When this option is specified, either the --incremental-lsn or --incremental-basedir options can also be given. If neither option is given, --incremental-basedir is used by default, set to the first timestamped backup directory in the backup base directory.

    If a backup is a incremental backup, then mariadb-backup records that detail in the xtrabackup_info file.

    Defines whether you want to take an incremental backup, based on another backup.

    Using this option with the --backup option makes the operation incremental rather than a complete overwrite. mariadb-backup only copies pages from .ibd files if they are newer than the backup in the specified directory.

    If a backup is a incremental backup, then mariadb-backup records that detail in the xtrabackup_info file.

    Defines whether you want to take an incremental backup, based on another backup.

    Using this option with --prepare command option makes the operation incremental rather than a complete overwrite. mariadb-backup will apply .delta files and log files into the target directory.

    If a backup is a incremental backup, then mariadb-backup records that detail in the xtrabackup_info file.

    Defines whether you want to force a full scan for incremental backups.

    When using mariadb-backup to perform an incremental backup, this option forces it to also perform a full scan of the data pages being backed up, even when there's bitmap data on the changes. MariaDB does not support changed page bitmaps, so this option is useless in those versions. See for more information.

    Defines a logical name for the backup.

    mariadb-backup can store data about its operations on the MariaDB Server. Using this option, you can define the logical name it uses in identifying the backup.

    The table it uses by default is named mysql.mariadb_backup_history. Prior to , the default table was PERCONA_SCHEMA.xtrabackup_history.

    mariadb-backup also records this in the xtrabackup_info file.

    Defines a UUID for the backup.

    mariadb-backup can store data about its operations on the MariaDB Server. Using this option, you can define the UUID it uses in identifying a previous backup to increment from. It checks --incremental-history-name, --incremental-basedir, and --incremental-lsn. If mariadb-backup fails to find a valid lsn, it generates an error.

    The table it uses is named PERCONA_SCHEMA.xtrabackup_history, but expect that name to change in future releases. See for more information.

    Table Name and Schema Changes (MariaDB 10.11):

    • MariaDB 10.11 and later: Uses mysql.mariadb_backup_history (InnoDB).

    • MariaDB 10.10 and earlier: Uses PERCONA_SCHEMA.xtrabackup_history (CSV).

    mariadb-backup also records this in the xtrabackup_info file.

    Defines the sequence number for incremental backups.

    Using this option, you can define the sequence number (LSN) value for --backup operations. During backups, mariadb-backup only copies .ibd pages newer than the specified values.

    Use to enable innobackupex mode, which is a compatibility mode.

    This option has no effect. Set only for MySQL option compatibility.

    Enables InnoDB Adaptive Hash Index.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option you can explicitly enable the InnoDB Adaptive Hash Index. This feature is enabled by default for mariadb-backup. If you want to disable it, use --skip-innodb-adaptive-hash-index.

    Defines the increment in megabytes for auto-extending the size of tablespace file.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can set the increment in megabytes for automatically extending the size of tablespace data file in InnoDB.

    Using this option has no effect. It is available to provide compatibility with the MariaDB Server.

    Defines the memory buffer size InnoDB uses the cache data and indexes of the table.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can configure the buffer pool for InnoDB operations.

    innodb_checksum_algorithm has been removed.

    Defines the path to individual data files.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option you can define the path to InnoDB data files. Each path is appended to the --innodb-data-home-dir option.

    Defines the home directory for InnoDB data files.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option you can define the path to the directory containing InnoDB data files. You can specific the files using the --innodb-data-file-path option.

    Enables doublewrites for InnoDB tables.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. When using this option, mariadb-backup improves fault tolerance on InnoDB tables with a doublewrite buffer. By default, this feature is enabled. Use this option to explicitly enable it. To disable doublewrites, use the --skip-innodb-doublewrite option.

    Defines whether you want to encrypt InnoDB logs.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can tell mariadb-backup that you want to encrypt logs from its InnoDB activity.

    Defines the number of file I/O threads in InnoDB.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the number of file I/O threads mariadb-backup uses on InnoDB tables.

    Defines whether you want to store each InnoDB table as an .ibd file.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option causes mariadb-backup to store each InnoDB table as an .ibd file in the target directory.

    Defines the data flush method. Ignored from . For the OS-level mechanisms behind these flag names, see .

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the data flush method mariadb-backup uses with InnoDB tables.

    Defines the number of IOP's the utility can perform.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can limit the I/O activity for InnoDB background tasks. It should be set around the number of I/O operations per second that the system can handle, based on drive or drives being used.

    The size of the buffer that will be used for reading log during mariadb-backup --prepare. Ignored when using --innodb-log-file-mmap.

    Defines whether to include checksums in the InnoDB logs.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can explicitly set mariadb-backup to include checksums in the InnoDB logs. The feature is enabled by default. To disable it, use the --skip-innodb-log-checksums option.

    At the start of a backup, instruct the server to write out all modified pages to the data files, to minimize the size of the ib_logfile0 that needs to be copied.

    When this option is enabled, mariadb-backup reads the ib_logfile0 via a memory mapping, rather than by reading into a separately allocated buffer of --innodb-log-buffer-size.

    This option has no functionality in mariadb-backup. It exists for MariaDB Server compatibility.

    Defines the path to InnoDB log files.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the path to InnoDB log files.

    Defines the percentage of dirty pages allowed in the InnoDB buffer pool.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the maximum percentage of dirty, (that is, unwritten) pages that mariadb-backup allows in the InnoDB buffer pool.

    Defines the number of files kept open at a time.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can set the maximum number of files InnoDB keeps open at a given time during backups.

    Defines the universal page size.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the universal page size in bytes for mariadb-backup.

    Defines the number of background read I/O threads in InnoDB.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can set the number of I/O threads MariaDB uses when reading from InnoDB.

    Defines the directory for the undo tablespace files.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the path to the directory where you want MariaDB to store the undo tablespace on InnoDB tables. The path can be absolute.

    Defines the number of undo tablespaces to use.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can define the number of undo tablespaces you want to use during the backup.

    Defines whether you want to use native AI/O.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can enable the use of the native asynchronous I/O subsystem. It is only available on Linux operating systems.

    Defines the number of background write I/O threads in InnoDB.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can set the number of background write I/O threads mariadb-backup uses.

    Defines the timeout for blocking queries.

    When mariadb-backup runs, it issues a FLUSH TABLES WITH READ LOCK statement. It then identifies blocking queries. Using this option you can set a timeout in seconds for these blocking queries. When the time runs out, mariadb-backup kills the queries.

    The default value is 0, which causes mariadb-backup to not attempt killing any queries.

    Defines the query type the utility can kill to unblock the global lock.

    When mariadb-backup encounters a query that sets a global lock, it can kill the query in order to free up MariaDB Server for the backup. Using this option, you can choose the types of query it kills: SELECT, UPDATE, or both set with ALL. The default is ALL.

    Prevents DDL for each table to be backed up by acquiring MDL lock on that.

    This option has no functionality. It is set to ensure compatibility with MySQL.

    Defines the base name for the log sequence.

    Using this option you, you can set the base name for mariadb-backup to use in log sequences.

    Defines the copy interval between checks done by the log copying thread.

    Using this option, you can define the copy interval mariadb-backup uses between checks done by the log copying thread. The given value is in milliseconds.

    Continue backup if InnoDB corrupted pages are found. The pages are logged in innodb_corrupted_pages and backup is finished with error. --prepare will try to fix corrupted pages. If innodb_corrupted_pages exists after --prepare in base backup directory, backup still contains corrupted pages and can not be considered as consistent.

    Restores the backup to the data directory.

    Using this command, mariadb-backup moves the backup from the target directory to the data directory, as defined by the --datadir option. You must stop the MariaDB Server before running this command. The data directory must be empty. If you want to overwrite the data directory with the backup, use the --force-non-empty-directories option.

    Bear in mind, before you can restore a backup, you first need to run mariadb-backup with the --prepare option. In the case of full backups, this makes the files point-in-time consistent. With incremental backups, this applies the deltas to the base backup. Once the backup is prepared, you can run --move-back to apply it to MariaDB Server.

    Running the --move-back command moves the backup files to the data directory. Use this command if you don't want to save the backup for later. If you do want to save the backup for later, use the --copy-back option.

    Used internally to prepare a backup.

    mariadb-backup locks the database by default when it runs. This option disables support for Percona Server's backup locks.

    When backing up Percona Server, mariadb-backup would use backup locks by default. To be specific, backup locks refers to the LOCK TABLES FOR BACKUP and LOCK BINLOG FOR BACKUP statements. This option can be used to disable support for Percona Server's backup locks. This option has no effect when the server does not support Percona's backup locks.

    Deprecated and has no effect from , , and as MariaDB now always uses backup locks for better performance. See .

    Disables table locks with the FLUSH TABLE WITH READ LOCK statement.

    Using this option causes mariadb-backup to disable table locks with the FLUSH TABLE WITH READ LOCK statement. Only use this option if:

    • You are not executing DML statements on non-InnoDB tables during the backup. This includes the mysql database system tables (which are MyISAM).

    • You are not executing any DDL statements during the backup.

    • You are not using the file xtrabackup_binlog_info, which is not consistent with the data when --no-lock

    If you're considering --no-lock due to backups failing to acquire locks, this may be due to incoming replication events preventing the lock. Consider using the --safe-slave-backup option to momentarily stop the replica thread. This alternative may help the backup to succeed without resorting to --no-lock.

    The --no-lock option only provides a consistent backup if the user ensures that no DDL or non-transactional table updates occur during the backup. The --no-lock option is not supported by MariaDB plc.

    This option prevents creation of a time-stamped subdirectory of the BACKUP-ROOT-DIR given on the command line. When it is specified, the backup is done in BACKUP-ROOT-DIR instead. This is only valid in innobackupex mode, which can be enabled with the --innobackupex option.

    Disables version check.

    Using this option, you can disable mariadb-backup version check.

    Defines the maximum number of file descriptors.

    Using this option, you can define the maximum number of file descriptors mariadb-backup reserves with setrlimit().

    Defines the number of threads to use for parallel data file transfer.

    Using this option, you can set the number of threads mariadb-backup uses for parallel data file transfers. By default, it is set to 1.

    Defines the password to use to connect to MariaDB Server.

    When you run mariadb-backup, it connects to MariaDB Server in order to access and back up the databases and tables. Using this option, you can set the password mariadb-backup uses to access the server. To set the user, use the --user option.

    Defines the directory for server plugins.

    Using this option, you can define the path mariadb-backup reads for MariaDB Server plugins. It only uses it during the --prepare phase to load the encryption plugin. It defaults to the plugin_dir server system variable.

    The option has been removed.

    Defines the server port to connect to.

    When you run mariadb-backup, it connects to MariaDB Server in order to access and back up your databases and tables. Using this option, you can set the port the utility uses to access the server over TCP/IP. To set the host, see the --host option. Use mysql --help for more details.

    Prepares an existing backup to restore to the MariaDB Server.

    Files that mariadb-backup generates during --backup operations in the target directory are not ready for use on the Server. Before you can restore the data to MariaDB, you first need to prepare the backup.

    In the case of full backups, the files are not point in time consistent, since they were taken at different times. If you try to restore the database without first preparing the data, InnoDB rejects the new data as corrupt. Running mariadb-backup with the --prepare command readies the data so you can restore it to MariaDB Server. When working with incremental backups, you need to use the --prepare command and the --incremental-dir option to update the base backup with the deltas from an incremental backup.

    Once the backup is ready, you can use the --copy-back or the --move-back options to restore the backup to the server.

    Prints the utility argument list, then exits.

    Using this argument, MariaDB prints the argument list to stdout and then exits. You may find this useful in debugging to see how the options are set for the utility.

    Prints the MariaDB Server options needed for copy-back.

    Using this option, mariadb-backup prints to stdout the MariaDB Server options that the utility requires to run the --copy-back command option.

    By default, mariadb-backup will not commit or rollback uncommitted XA transactions, and when the backup is restored, any uncommitted XA transactions must be manually committed using XA COMMIT or manually rolled back using XA ROLLBACK.

    MariaDB starting with

    mariadb-backup's --rollback-xa option is not present because the server has more robust ways of handling uncommitted XA transactions.

    This is an experimental option. Do not use this option in older versions. Older implementation can cause corruption of InnoDB data.

    Defines whether to use rsync.

    During normal operation, mariadb-backup transfers local non-InnoDB files using a separate call to cp for each file. Using this option, you can optimize this process by performing this transfer with rsync, instead.

    This option is not compatible with the --stream option.

    Deprecated and has no effect from , , and as rsync will not work on tables that are in use. See .

    Stops replica SQL threads for backups.

    When running mariadb-backup on a server that uses replication, you may occasionally encounter locks that block backups. Using this option, it stops replica SQL threads and waits until the Slave_open_temp_tables in the SHOW STATUS statement is zero. If there are no open temporary tables, the backup runs, otherwise the SQL thread starts and stops until there are no open temporary tables.

    The backup fails if the Slave_open_temp_tables doesn't reach zero after the timeout period set by the --safe-slave-backup-timeout option.

    Defines the timeout for replica backups.

    When running mariadb-backup on a server that uses replication, you may occasionally encounter locks that block backups. With the --safe-slave-backup option, it waits until the Slave_open_temp_tables in the SHOW STATUS statement reaches zero. Using this option, you set how long it waits. It defaults to 300.

    Refuses client connections to servers using the older protocol.

    Using this option, you can set it explicitly to refuse client connections to the server when using the older protocol, from before 4.1.1. This feature is enabled by default. Use the --skip-secure-auth option to disable it.

    Disables InnoDB Adaptive Hash Index.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option you can explicitly disable the InnoDB Adaptive Hash Index. This feature is enabled by default for mariadb-backup. If you want to explicitly enable it, use --innodb-adaptive-hash-index.

    Disables doublewrites for InnoDB tables.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. When doublewrites are enabled, InnoDB improves fault tolerance with a doublewrite buffer. By default this feature is turned on. Using this option you can disable it for mariadb-backup. To explicitly enable doublewrites, use the --innodb-doublewrite option.

    Defines whether to exclude checksums in the InnoDB logs.

    mariadb-backup initializes its own embedded instance of InnoDB using the same configuration as defined in the configuration file. Using this option, you can set mariadb-backup to exclude checksums in the InnoDB logs. The feature is enabled by default. To explicitly enable it, use the --innodb-log-checksums option.

    Refuses client connections to servers using the older protocol.

    Using this option, you can set it accept client connections to the server when using the older protocol, from before 4.1.1. By default, it refuses these connections. Use the --secure-auth option to explicitly enable it.

    Prints the binary log position and the name of the primary server.

    If the server is a replica, then this option causes mariadb-backup to print the hostname of the replica's replication primary and the binary log file and position of the replica's SQL thread to stdout.

    This option also causes mariadb-backup to record this information as a CHANGE MASTER statement that can be used to set up a new server as a replica of the original server's primary after the backup has been restored. This information are written to the xtrabackup_slave_info file.

    mariadb-backup does not check if GTIDs are being used in replication. It takes a shortcut and assumes that if the gtid_slave_pos system variable is non-empty, then it writes the CHANGE MASTER statement with the MASTER_USE_GTID option set to slave_pos. Otherwise, it writes the CHANGE MASTER statement with the MASTER_LOG_FILE and MASTER_LOG_POS options using the primary's binary log file and position. See for more information.

    Defines the socket for connecting to local database.

    Using this option, you can define the UNIX domain socket you want to use when connecting to a local database server. The option accepts a string argument. For more information, see the mysql --help command.

    Enables TLS. By using this option, you can explicitly configure mariadb-backup to encrypt its connection with TLS when communicating with the server. You may find this useful when performing backups in environments where security is extra important or when operating over an insecure network.

    TLS is also enabled even without setting this option when certain other TLS options are set. For example, see the descriptions of the following options:

    • --ssl-ca

    • --ssl-capath

    • --ssl-cert

    • --ssl-cipher

    Defines a path to a PEM file that should contain one or more X509 certificates for trusted Certificate Authorities (CAs) to use for TLS. This option requires that you use the absolute path, not a relative path. For example:

    This option is usually used with other TLS options. For example:

    See Secure Connections Overview: Certificate Authorities (CAs) for more information.

    This option implies the --ssl option.

    Defines a path to a directory that contains one or more PEM files that should each contain one X509 certificate for a trusted Certificate Authority (CA) to use for TLS. This option requires that you use the absolute path, not a relative path. For example:

    This option is usually used with other TLS options. For example:

    The directory specified by this option needs to be run through the command.

    See Secure Connections Overview: Certificate Authorities (CAs) for more information

    This option implies the --ssl option.

    Defines a path to the X509 certificate file to use for TLS. This option requires that you use the absolute path, not a relative path. For example:

    This option is usually used with other TLS options. For example:

    This option implies the --ssl option.

    Defines the list of permitted ciphers or cipher suites to use for TLS. For example:

    This option is usually used with other TLS options. For example:

    To determine if the server restricts clients to specific ciphers, check the ssl_cipher system variable.

    This option implies the --ssl option.

    Defines a path to a PEM file that should contain one or more revoked X509 certificates to use for TLS. This option requires that you use the absolute path, not a relative path. For example:

    This option is usually used with other TLS options. For example:

    See Secure Connections Overview: Certificate Revocation Lists (CRLs) for more information.

    This option is only supported if mariadb-backup was built with OpenSSL. If mariadb-backup was built with yaSSL, then this option is not supported. See TLS and Cryptography Libraries Used by MariaDB for more information about which libraries are used on which platforms.

    Defines a path to a directory that contains one or more PEM files that should each contain one revoked X509 certificate to use for TLS. This option requires that you use the absolute path, not a relative path. For example:

    This option is usually used with other TLS options. For example:

    The directory specified by this option needs to be run through the command.

    See Secure Connections Overview: Certificate Revocation Lists (CRLs) for more information.

    This option is only supported if mariadb-backup was built with OpenSSL. If mariadb-backup was built with yaSSL, then this option is not supported. See TLS and Cryptography Libraries Used by MariaDB for more information about which libraries are used on which platforms.

    Defines a path to a private key file to use for TLS. This option requires that you use the absolute path, not a relative path. For example:

    This option is usually used with other TLS options. For example:

    This option implies the --ssl option.

    Enables server certificate verification. This option is disabled by default.

    This option is usually used with other TLS options. For example:

    Streams backup files to stdout.

    Using this command option, you can set mariadb-backup to stream the backup files to stdout in the given format. Currently, the supported format is xbstream.

    To extract all files from the xbstream archive into a directory use the mbstream utility

    If a backup is streamed, then mariadb-backup records the format in the xtrabackup_info file.

    Defines the tables you want to include in the backup.

    Using this option, you can define what tables you want mariadb-backup to back up from the database. The table values are defined using Regular Expressions (regex). To define the tables you want to exclude from the backup, see the --tables-exclude option.

    In the example, nodes_* matches tables named nodes, nodes_, nodes__, and so forth, because * means zero or more occurrences of the previous character (_).

    If instead you want to back up all tables whose names start with nodes, the regular expression is ^nodes., and to exclude tables starting with nodes_tmp, the expression is ^nodes_tmp.. (Notice the trailing period (.); it means zero or more occurrences of characters following nodes.) The command looks like this:

    In that example, some of the tables included via the --tables option are excluded by --tables-excludes. That works because --tables-exclude takes precedence over --tables.

    You can specify multiple table name regex patterns as a comma-separated list, for both the --tables and the --tables-exclude options.

    The following command backs up all tables in the test1 and test2 databases, except the exclude_table table in the test2 database, and stores the backup files under /path/to/backups/:

    If a backup is a partial backup, mariadb-backup records that detail in the xtrabackup_info file.

    Defines the tables you want to exclude from the backup.

    Using this option, you can define what tables you want mariadb-backup to exclude from the backup. The table values are defined using Regular Expressions. To define the tables you want to include from the backup, see the --tables option.

    If a backup is a partial backup, mariadb-backup records that detail in the xtrabackup_info file.

    Defines path to file with tables for backups.

    Using this option, you can set a path to a file listing the tables you want to back up. mariadb-backup iterates over each line in the file. The format is database.table.

    If a backup is a partial backup, then mariadb-backup will record that detail in the xtrabackup_info file.

    Defines the destination directory.

    Using this option you can define the destination directory for the backup. mariadb-backup writes all backup files to this directory. mariadb-backup will create the directory, if it does not exist (but it does not create the full path recursively, i.e. at least parent directory if the --target-dir must exist.

    Defines the limit for I/O operations per second in IOS values.

    Using this option, you can set a limit on the I/O operations mariadb-backup performs per second in IOS values. It is only used during the --backup option.

    This option accepts a comma-separated list of TLS protocol versions. A TLS protocol version is only enabled if it is present in this list. All other TLS protocol versions will not be permitted. For example:

    This option is usually used with other TLS options. For example:

    See Secure Connections Overview: TLS Protocol Versions for more information.

    Defines path for temporary files.

    Using this option, you can define the path to a directory mariadb-backup uses in writing temporary files. If you want to use more than one, separate the values by a semicolon (that is, ;). When passing multiple temporary directories, it cycles through them using round-robin.

    Defines the buffer pool size that is used during the prepare stage.

    Using this option, you can define the buffer pool size for mariadb-backup. Use it instead of buffer_pool_size.

    Defines the username for connecting to the MariaDB Server.

    When mariadb-backup runs, it connects to the specified MariaDB Server to get its backups. Using this option, you can define the database user used for authentication. Starting from , , , , , , , if the --user option is omitted, the user name is detected from the OS.

    Displays verbose output.

    Prints the mariadb-backup version information to stdout.

    This page is licensed: CC BY-SA / Gnu FDL

    CREATE TABLE

    Complete guide to creating tables in MariaDB. Complete CREATE TABLE syntax for data types, constraints, indexes, and storage engines for production use.

    Syntax

    CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        (create_definition,...) [table_options    ]... [partition_options]
    CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        [(create_definition,...)] [table_options   ]... [partition_options]
        select_statement
    CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
       { LIKE old_table_name | (LIKE old_table_name) }
    
    select_statement:
        [IGNORE | REPLACE] [AS] SELECT ...   (Some legal select statement)

    Description

    Use the CREATE TABLE statement to create a table with the given name.

    In its most basic form, the CREATE TABLE statement provides a table name followed by a list of columns, indexes, and constraints. By default, the table is created in the default database. Specify a database with db_name.tbl_name. If you quote the table name, you must quote the database name and table name separately as `db_name`.`tbl_name`. This is particularly useful for CREATE TABLE ... SELECT, because it allows creating a table in a database that contains data from other databases. See Identifier Qualifiers.

    If a table with the same name exists, error 1050 results. Use IF NOT EXISTS to suppress this error and issue a note instead. Use SHOW WARNINGS to see notes.

    The CREATE TABLE statement automatically commits the current transaction, except when using the keyword.

    For valid identifiers to use as table names, see .

    can be between 0-6. If no precision is specified, it is assumed to be 0, for backward compatibility reasons.

    Executing the CREATE TABLE statement requires the privilege for the table or the database.

    If the OR REPLACE clause is used and the table already exists, then instead of returning an error, the server will drop the existing table and replace it with the newly defined table.

    This syntax was originally added to make more robust if it has to rollback and repeat statements such as CREATE ... SELECT on replicas.

    is basically the same as:

    with the following exceptions:

    • If table_name was locked with , it will continue to be locked after the statement.

    • Temporary tables are only dropped if the TEMPORARY keyword was used. (With , temporary tables are preferred to be dropped before normal tables).

    • The table is dropped first (if it existed), and after that, the CREATE is done. Because of this, if the CREATE fails, then the table will not exist anymore after the statement. If the table was used with LOCK TABLES, it will be unlocked.

    • One can't use OR REPLACE together with IF EXISTS.

    If the IF NOT EXISTS clause is used, then the table will only be created if a table with the same name does not already exist. If the table already exists, then a warning will be triggered by default.

    Use the TEMPORARY keyword to create a temporary table that is only available to the current session. Temporary tables are dropped when the session ends. Temporary table names are specific to the session. They will not conflict with other temporary tables from other sessions, even if they share the same name. They will shadow names of non-temporary tables or views, if they are identical. A temporary table can have the same name as a non-temporary table, which is located in the same database. In that case, their name will reference the temporary table when used in SQL statements. You must have the privilege on the database to create temporary tables. If no storage engine is specified, the setting will determine the engine.

    temporary tables cannot be created by setting the system variable or using CREATE TEMPORARY TABLE LIKE. If you try, an error is returned. Explicitly creating a temporary table with ENGINE=ROCKSDB has never been permitted.

    temporary tables cannot be created by setting the system variable, or using CREATE TEMPORARY TABLE LIKE. They can be specified, but fail silently, and a MyISAM table is created instead. Explicitly creating a temporary table with ENGINE=ROCKSDB has never been permitted.

    By default, temporary tables are only created on the replica if the primary is using the .

    The new deterministic rules for logging of temporary tables are:

    • The STATEMENT binlog format is used. The user can change this behavior by setting to MIXED, STATEMENT in which case the create is logged in statement format also in MIXED mode (as before).

    Use the LIKE clause instead of a full table definition to create an empty table with the same definition as another table, including columns, indexes, and table options. Foreign key definitions, as well as any DATA DIRECTORY or INDEX DIRECTORY table options specified on the original table, will not be created.

    LIKE does not preserve the TEMPORARY status of the original table. To make the new table TEMPORARY as well, use CREATE TEMPORARY TABLE ... LIKE.

    LIKE does not work with , only base tables. Attempting to use it on a view will result in an error:

    The same version of the table storage format as found in the original table is used for the new table.

    CREATE TABLE ... LIKE performs the same checks as CREATE TABLE. So a statement may fail if a change in the renders it invalid. For example:

    You can create a table containing data from other tables using the CREATE ... SELECT statement. Columns will be created in the table for each field returned by the SELECT query.

    You can also define some columns normally and add other columns from a SELECT. You can also create columns in the normal way and assign them some values using the query, this is done to force a certain type or other field characteristics. The columns that are not named in the query will be placed before the others. For example:

    Remember that the query just returns data. If you want to use the same indexes or the same column attributes ([NOT] NULL, DEFAULT, AUTO_INCREMENT, CHECK constraints) in the new table, you need to specify them manually. Types and sizes are not automatically preserved if no data is returned by the SELECT that requires the full size, and VARCHAR could be converted into CHAR. The function can be used to force the new table to use certain types.

    Aliases (AS) are taken into account, and they should always be used when you SELECT an expression (function, arithmetical operation, etc.).

    If an error occurs during the query, the table will not be created at all.

    If the new table has a primary key or UNIQUE indexes, you can use the or REPLACE keywords to handle duplicate key errors during the query. IGNORE means that the newer values must not be inserted if an identical value exists in the index. REPLACE means that older values must be overwritten.

    If the columns in the new table are more than the rows returned by the query, the columns populated by the query will be placed after the other columns. Note that if the strict SQL_MODE is on, and the columns that are not named in the query do not have a DEFAULT value, an error will be raised and no rows will be copied.

    are not used during the execution of a CREATE ... SELECT.

    If the table already exists, an error similar to the following will be returned:

    If the IF NOT EXISTS clause is used, and the table exists, a note will be produced instead of an error.

    To insert rows from a query into an existing table, can be used.

    MariaDB accepts the shortcut format with a REFERENCES clause only in ALTER TABLE and CREATE TABLE statements, but that syntax does nothing. For example:

    MariaDB will attempt to apply the constraint. See .

    MariaDB accepts the shortcut format with a REFERENCES clause only in ALTER TABLE and CREATE TABLE statements, but that syntax does nothing. For example:

    Each definition either creates a column in the table or specifies an index or constraint on one or more columns. See below for details on creating indexes.

    Create a column by specifying a column name and a data type, optionally followed by column options. See for a full list of data types allowed in MariaDB.

    Use the NULL or NOT NULL options to specify that values in the column may or may not be NULL, respectively. By default, values may be NULL. See also .

    Specify a default value using the DEFAULT clause. If you don't specify DEFAULT then the following rules apply:

    • If the column is not defined with NOT NULL, AUTO_INCREMENT or TIMESTAMP, an explicit DEFAULT NULL will be added. Note that in MySQL, you may get an explicit DEFAULT for primary key parts, if not specified with NOT NULL.

    The default value will be used if you a row without specifying a value for that column, or if you specify for that column.

    may also be used as the default value for a

    You can use most functions in DEFAULT. Expressions should have parentheses around them. If you use a non deterministic function in DEFAULT then all inserts to the table will be in . You can even refer to earlier columns in the DEFAULT expression (excluding AUTO_INCREMENT columns):

    The DEFAULT clause cannot contain any or , and a column used in the clause must already have been defined earlier in the statement.

    It is possible to assign or columns a DEFAULT value.

    You can also use DEFAULT ().

    Use to create a column whose value can be set automatically from a simple counter. You can only use AUTO_INCREMENT on a column with an integer type. The column must be a key, and there can only be one AUTO_INCREMENT column in a table. If you insert a row without specifying a value for that column (or if you specify 0, NULL, or as the value), the actual value will be taken from the counter, with each insertion incrementing the counter by one. You can still insert a value explicitly. If you insert a value that is greater than the current counter value, the counter is set based on the new value. An AUTO_INCREMENT column is implicitly NOT NULL. Use to get the value most recently used by an statement.

    If the ZEROFILL column option is specified for a column using a data type, then the column will be set to UNSIGNED and the spaces used by default to pad the field are replaced with zeros. ZEROFILL is ignored in expressions or as part of a , , or . ZEROFILL is a non-standard MariaDB and MySQL extension.

    Use PRIMARY KEY to make a column a primary key. A primary key is a special type of a unique key. There can be at most one primary key per table, and it is implicitly NOT NULL.

    Specifying a column as a unique key creates a unique index on that column. See the section below for more information.

    Use UNIQUE KEY (or just UNIQUE) to specify that all values in the column must be distinct from each other. Unless the column is NOT NULL, there may be multiple rows with NULL in the column.

    When any inserts or updates occur in the table, reading the binlog shows the hidden column (@3). it causes confusion for the user; we can document these behaviours.

    See the section below for more information.

    You can provide a comment for each column using the COMMENT clause. The maximum length is 1024 characters. Use the statement to see column comments.

    REF_SYSTEM_ID can be used to specify Spatial Reference System IDs for spatial data type columns. For example:

    A generated column is a column in a table that cannot explicitly be set to a specific value in a . Instead, its value is automatically generated based on an expression. This expression might generate the value based on the values of other columns in the table, or it might generate the value by calling or .

    There are two types of generated columns:

    • PERSISTENT or STORED: This type's value is actually stored in the table.

    • VIRTUAL: This type's value is not stored at all. Instead, the value is generated dynamically when the table is queried. This type is the default.

    Generated columns are also sometimes called computed columns or virtual columns.

    For a complete description about generated columns and their limitations, see .

    Certain columns may be compressed. See .

    Columns may be made invisible, and hidden in certain contexts. See .

    Columns may be explicitly marked as included from system versioning. See for details.

    Columns may be explicitly marked as excluded from system versioning. See for details.

    INDEX and KEY are synonyms.

    Index names are optional, if not specified an automatic name will be assigned. Index name are needed to drop indexes and appear in error messages when a constraint is violated.

    For limits on InnoDB indexes, see .

    Plain indexes are regular indexes that are not unique, and are not acting as a primary key or a foreign key. They are also not the "specialized" FULLTEXT or SPATIAL indexes.

    See for more information.

    For PRIMARY KEY indexes, you can specify a name for the index, but it is ignored, and the name of the index is always PRIMARY. A warning is explicitly issued if a name is specified. Before then, the name was silently ignored.

    See for more information.

    The UNIQUE keyword means that the index will not accept duplicated values, except for NULLs. An error will raise if you try to insert duplicate values in a UNIQUE index.

    For UNIQUE indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages.

    -

    See for more information.

    For FOREIGN KEY indexes, a reference definition must be provided.

    For FOREIGN KEY indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages.

    First, you have to specify the name of the target (parent) table and a column or a column list which must be indexed and whose values must match to the foreign key's values. The MATCH clause is accepted to improve the compatibility with other DBMS's, but has no meaning in MariaDB. The ON DELETE and ON UPDATE clauses specify what must be done when a DELETE (or a REPLACE) statements attempts to delete a referenced row from the parent table, and when an UPDATE statement attempts to modify the referenced foreign key columns in a parent table row, respectively. The following options are allowed:

    • RESTRICT: The delete/update operation is not performed. The statement terminates with a 1451 error (SQLSTATE '2300').

    • NO ACTION: Synonym for RESTRICT.

    • CASCADE

    If either clause is omitted, the default behavior for the omitted clause is RESTRICT.

    See for more information.

    Use the FULLTEXT keyword to create full-text indexes.

    See for more information.

    Use the SPATIAL keyword to create geometric indexes.

    See for more information.

    The KEY_BLOCK_SIZE index option is similar to the table option.

    With the storage engine, if you specify a non-zero value for the KEY_BLOCK_SIZE table option for the whole table, then the table will implicitly be created with the table option set to COMPRESSED. However, this does not happen if you just set the KEY_BLOCK_SIZE index option for one or more indexes in the table. The storage engine ignores the KEY_BLOCK_SIZE index option. However, the statement may still report it for the index.

    For information about the KEY_BLOCK_SIZE index option, see the table option below.

    The ADAPTIVE_HASH_INDEX index option takes the same DEFAULT, YES, and NO values as the table option, but applies to a single index. When set to YES or NO, it overrides the table-level setting for that index. This option applies only to .

    Three additional index options give fine-grained control over how the adaptive hash index is built for an index:

    Option
    Values
    Effect

    The default for all three is unset (automatic), in which case InnoDB chooses the values from its internal heuristic.

    The main reason to fix these values is to avoid adaptive-hash-index churn: when an index's lookup pattern is not constant, the internal heuristic keeps changing its parameters, repeatedly destroying and rebuilding the hash index. Pinning the parameters keeps a single hash index in place — less optimal for some queries, but stable and beneficial for the rest, instead of being continually rebuilt.

    These options apply only to , and only on servers built with adaptive hash index support.

    Each storage engine supports some or all index types. See for details on permitted index types for each storage engine.

    Different index types are optimized for different kind of operations:

    • BTREE is the default type, and normally is the best choice. It is supported by all storage engines. It can be used to compare a column's value with a value using the =, >, >=, <, <=, BETWEEN, and LIKE operators. BTREE can also be used to find NULL values. Searches against an index prefix are possible.

    • HASH is only supported by the MEMORY storage engine.

    Index columns names are listed between parenthesis. After each column, a prefix length can be specified. If no length is specified, the whole column will be indexed. ASC and DESC can be specified. Individual columns in the index can be explicitly sorted in ascending or descending order. This can be useful for optimizing certain ORDER BY cases (, , , ). Not only ascending, but also descending, indexes can be used to optimize and ().

    Index columns names are listed between parenthesis. After each column, a prefix length can be specified. If no length is specified, the whole column will be indexed. ASC and DESC can be specified. Prior to , this was only for compatibility with other DBMSs, but had no meaning in MariaDB. From , individual columns in the index can now be explicitly sorted in ascending or descending order. This can be useful for optimizing certain ORDER BY cases (,

    The maximum number of parts in an index is 32.

    The WITH PARSER index option only applies to indexes and contains the fulltext parser name. The fulltext parser must be an installed plugin.

    Indexes can be declared visible. This is the default and it shows up in .

    Indexes cannot be declared visible.

    A comment of up to 1024 characters is permitted with the COMMENT index option.

    The COMMENT index option allows you to specify a comment with user-readable text describing what the index is for. This information is not used by the server itself.

    The CLUSTERING index option is only valid for tables using the storage engine.

    Indexes can be specified to be ignored by the optimizer. See .

    Indexes can be specified to be ignored by the optimizer. See .

    MariaDB supports , or .

    MariaDB introduced two ways to define a constraint:

    • CHECK(expression) given as part of a column definition.

    • CONSTRAINT [constraint_name] CHECK (expression)

    Before a row is inserted or updated, all constraints are evaluated in the order they are defined. If any constraints fails, then the row will not be updated. One can use most deterministic functions in a constraint, including .

    If you use the second format and you don't give a name to the constraint, then the constraint will get a auto generated name. This is done so that you can later delete the constraint with .

    One can disable all constraint expression checks by setting the variable check_constraint_checks to OFF. This is useful for example when loading a table that violates some constraints that you want to later find and fix in SQL.

    See for more information.

    For each individual table you create (or alter), you can set some table options. The general syntax for setting options is:

    The equal sign is optional.

    Some options are supported by the server and can be used for all tables, no matter what storage engine they use; other options can be specified for all storage engines, but have a meaning only for some engines. Also, engines can .

    If the IGNORE_BAD_TABLE_OPTIONS is enabled, wrong table options generate a warning; otherwise, they generate an error.

    [STORAGE] ENGINE specifies a for the table. If this option is not used, the default storage engine is used instead. That is, the session option value if it is set, or the value specified for the --default-storage-engine , or the default storage engine, . If the specified storage engine is not installed and active, the default value will be used, unless the NO_ENGINE_SUBSTITUTION is set (default). This is only true for CREATE TABLE, not for ALTER TABLE. For a list of storage engines that are present in your server, issue a .

    ADAPTIVE_HASH_INDEX controls whether the InnoDB adaptive hash index (AHI) is used for an individual table. It takes one of three values:

    • DEFAULT — no per-table preference: the table follows the global setting. This is the default, and removes the option from the stored table definition.

    • YES — request the adaptive hash index for this table. AHI is built for the table only when it is also enabled at the server level (innodb_adaptive_hash_index set to ON or IF_SPECIFIED).

    The option only affects tables, and only on servers built with adaptive hash index support. The same option can be set per index (see ); an index-level YES or NO overrides the table-level setting for that index.

    AUTO_INCREMENT specifies the initial value for the primary key. This works for MyISAM, Aria, InnoDB, MEMORY, and ARCHIVE tables. You can change this option with ALTER TABLE, but in that case the new value must be higher than the highest value which is present in the AUTO_INCREMENT column. If the storage engine does not support this option, you can insert (and then delete) a row having the wanted value - 1 in the AUTO_INCREMENT column.

    AVG_ROW_LENGTH is the average rows size. It only applies to tables using and storage engines that have the table option set to FIXED format.

    MyISAM uses MAX_ROWS and AVG_ROW_LENGTH to decide the maximum size of a table (default: 256TB, or the maximum file size allowed by the system).

    [DEFAULT] CHARACTER SET (or [DEFAULT] CHARSET) is used to set a default character set for the table. This is the character set used for all columns where an explicit character set is not specified. If this option is omitted or DEFAULT is specified, the database's default character set will be used (except for the , which is utf8mb4 by default). See for details on setting the .

    CHECKSUM (or TABLE_CHECKSUM) can be set to 1 to maintain a live checksum for all table's rows. This makes write operations slower, but will be very fast. This option is only supported for and .

    [DEFAULT] COLLATE is used to set a default collation for the table. This is the collation used for all columns where an explicit character set is not specified. If this option is omitted or DEFAULT is specified, the database's default option will be used (except for the , which uses utf8mb4_bin by default). See for details on setting the

    COMMENT is a comment for the table. The maximum length is 2048 characters. Also used to define table parameters when creating a table.

    CONNECTION is used to specify a server name or a connection string for a , , .

    DATA DIRECTORY and INDEX DIRECTORY are supported for MyISAM and Aria, and DATA DIRECTORY is also supported by InnoDB if the server system variable is enabled, but only in CREATE TABLE, not in . So, carefully choose a path for InnoDB tables at creation time, because it cannot be changed without dropping and re-creating the table. These options specify the paths for data files and index files, respectively. If these options are omitted, the database's directory will be used to store data files and index files. Note that these table options do not work for tables (use the partition options instead), or if the server has been invoked with the . To avoid the overwriting of old files with the same name that could be present in the directories, you can use (an error will be issued if files already exist). These options are ignored if the NO_DIR_IN_CREATE is enabled (useful for replicas). Also note that symbolic links cannot be used for InnoDB tables.

    DATA DIRECTORY works by creating symlinks from where the table would normally have been (inside the ) to where the option specifies. For security reasons, to avoid bypassing the privilege system, the server does not permit symlinks inside the datadir. Therefore, DATA DIRECTORY cannot be used to specify a location inside the datadir. An attempt to do so will result in an error 1210 (HY000) Incorrect arguments to DATA DIRECTORY.

    DELAY_KEY_WRITE is supported by MyISAM and Aria, and can be set to 1 to speed up write operations. In that case, when data are modified, the indexes are not updated until the table is closed. Writing the changes to the index file altogether can be much faster. However, note that this option is applied only if the delay_key_write server variable is set to 'ON'. If it is 'OFF' the delayed index writes are always disabled, and if it is 'ALL' the delayed index writes are always used, disregarding the value of DELAY_KEY_WRITE.

    The ENCRYPTED table option can be used to manually set the encryption status of an table. See for more information.

    Aria does not support the ENCRYPTED table option. See .

    See for more information.

    The ENCRYPTION_KEY_ID table option can be used to manually set the encryption key of an table. See for more information.

    Aria does not support the ENCRYPTION_KEY_ID table option. See .

    See for more information.

    For the storage engine, the IETF_QUOTES option, when set to YES, enables IETF-compatible parsing of embedded quote and comma characters. Enabling this option for a table improves compatibility with other tools that use CSV, but is not compatible with MySQL CSV tables, or MariaDB CSV tables created without this option. Disabled by default.

    INSERT_METHOD is only used with tables. This option determines in which underlying table the new rows should be inserted. If you set it to 'NO' (which is the default) no new rows can be added to the table (but you will still be able to perform INSERTs directly against the underlying tables). FIRST means that the rows are inserted into the first table, and LAST means that they are inserted into the last table.

    KEY_BLOCK_SIZE is used to determine the size of key blocks, in bytes or kilobytes. However, this value is just a hint, and the storage engine could modify or ignore it. If KEY_BLOCK_SIZE is set to 0, the storage engine's default value will be used.

    With the storage engine, if you specify a non-zero value for the KEY_BLOCK_SIZE table option for the whole table, then the table will implicitly be created with the table option set to COMPRESSED.

    MIN_ROWS and MAX_ROWS let the storage engine know how many rows you are planning to store as a minimum and as a maximum. These values will not be used as real limits, but they help the storage engine to optimize the table. MIN_ROWS is only used by MEMORY storage engine to decide the minimum memory that is always allocated. MAX_ROWS is used to decide the minimum size for indexes.

    PACK_KEYS can be used to determine whether the indexes will be compressed. Set it to 1 to compress all keys. With a value of 0, compression will not be used. With the DEFAULT value, only long strings will be compressed. Uncompressed keys are faster.

    PAGE_CHECKSUM is only applicable to tables, and determines whether indexes and data should use page checksums for extra safety.

    PAGE_COMPRESSED is used to enable for tables.

    PAGE_COMPRESSION_LEVEL is used to set the compression level for for tables. The table must also have the table option set to 1.

    Valid values for PAGE_COMPRESSION_LEVEL are 1 (the best speed) through 9 (the best compression), .

    PASSWORD is unused.

    RAID_TYPE is an obsolete option, as the raid support has been disabled since MySQL 5.0.

    The ROW_FORMAT table option specifies the row format for the data file. Possible values are engine-dependent.

    For , the supported row formats are:

    • FIXED

    • DYNAMIC

    • COMPRESSED

    The COMPRESSED row format can only be set by the command line tool.

    See for more information.

    For , the supported row formats are:

    • PAGE

    • FIXED

    • DYNAMIC.

    See for more information.

    For , the supported row formats are:

    • COMPACT

    • REDUNDANT

    • COMPRESSED

    If the ROW_FORMAT table option is set to FIXED for an InnoDB table, then the server will either return an error or a warning depending on the value of the system variable. If the system variable is set to OFF, then a warning is issued, and MariaDB will create the table using the default row format for the specific MariaDB server version. If the system variable is set to ON, then an error will be raised.

    See for more information.

    Other storage engines do not support the ROW_FORMAT table option.

    If the table is a , then it will have the SEQUENCE set to 1.

    STATS_AUTO_RECALC indicates whether to automatically recalculate persistent statistics (see STATS_PERSISTENT, below) for an InnoDB table. If set to 1, statistics will be recalculated when more than 10% of the data has changed. When set to 0, stats will be recalculated only when an is run. If set to DEFAULT, or left out, the value set by the system variable applies. See .

    STATS_PERSISTENT indicates whether the InnoDB statistics created by will remain on disk or not. It can be set to 1 (on disk), 0 (not on disk, the pre-MariaDB 10 behavior), or DEFAULT (the same as leaving out the option), in which case the value set by the system variable will apply. Persistent statistics stored on disk allow the statistics to survive server restarts, and provide better query plan stability. See .

    STATS_SAMPLE_PAGES indicates how many pages are used to sample index statistics. If 0 or DEFAULT, the default value, the value is used. See .

    TRANSACTIONAL is only applicable for Aria tables. In future Aria tables created with this option will be fully transactional, but currently this provides a form of crash protection. See for more details.

    UNION must be specified when you create a MERGE table. This option contains a comma-separated list of MyISAM tables which are accessed by the new table. The list is enclosed between parenthesis. Example: UNION = (t1,t2)

    WITH SYSTEM VERSIONING is used for creating .

    If the PARTITION BY clause is used, the table will be . A partition method must be explicitly indicated for partitions and subpartitions. Partition methods are:

    • [LINEAR] creates a hash key which will be used to read and write rows. The partition function can be any valid SQL expression which returns an INTEGER number. Thus, it is possible to use the HASH method on an integer column, or on functions which accept integer columns as an argument. However, VALUES LESS THAN and VALUES IN clauses can not be used with HASH. An example:

    [LINEAR] can be used for subpartitions, too.

    • [LINEAR] is similar to HASH, but the index has an even distribution of data. Also, the expression can only be a column or a list of columns. VALUES LESS THAN and VALUES IN clauses can not be used with KEY.

    • partitions the rows using on a range of values, using the VALUES LESS THAN

    Only and can be used for subpartitions, and they can be [LINEAR].

    It is possible to define up to 8092 partitions and subpartitions.

    The number of defined partitions can be optionally specified as PARTITION count. This can be done to avoid specifying all partitions individually. But you can also declare each individual partition and, additionally, specify a PARTITIONS count clause; in the case, the number of PARTITIONs must equal count.

    Also see .

    The PARTITION keyword is optional as part of the partition definition. Instead of this:

    The following can be used:

    The PARTITION keyword is not optional as part of the partition definition. You must use this syntax:

    CREATE TABLE can also be used to create a . See and .

    MariaDB supports . CREATE TABLE is atomic, except for CREATE OR REPLACE, which are only crash-safe.

    -

    This example shows a couple of things:

    • Usage of IF NOT EXISTS; If the table already existed, it will not be created. There will not be any error for the client, just a warning.

    • How to create a PRIMARY KEY that is .

    • How to specify a table-specific and another for a column.

    The following clauses will work:

    This page is licensed: GPLv2, originally from

    AUTO

    Enables the retrieval of binary log information using ON or LOCKLESS where supported

    Defines whether you want to track backup history in the
    PERCONA_SCHEMA.xtrabackup_history
    table.

    When using this option, mariadb-backup records its operation in a table on the MariaDB Server. Passing a name to this option allows you group backups under arbitrary terms for later processing and analysis.

    Information is written to PERCONA_SCHEMA.xtrabackup_history.

    mariadb-backup also records this in the xtrabackup_info file.

    is used. Use the file
    xtrabackup_binlog_pos_innodb
    instead.
  • All tables you're backing up use the InnoDB storage engine.

  • --ssl-key

    mariadb-backup --backup --target-dir=/backups/full \
      --user=mariadb-backup --password=...
    mariadb-backup --prepare --target-dir=/backups/full
    mariadb-backup --copy-back --target-dir=/backups/full
    mariadb-backup --backup --target-dir=/backups/inc1 \
      --incremental-basedir=/backups/full
    mariadb-backup --innobackupex --apply-log
    mariadb-backup --backup 
          --target-dir /path/to/backup \
          --user user_name --password user_passwd
    --binlog-info[=OFF | ON | LOCKLESS | AUTO]

    OFF

    Disables the retrieval of binary log information

    ON

    Enables the retrieval of binary log information, performs locking where available to ensure consistency

    LOCKLESS

    Unsupported option

    mariadb-backup --binlog-info --backup
    mariadb-backup --close-files --prepare
    --compress[=compression_algorithm]

    quicklz

    Uses the QuickLZ compression algorithm

    mariadb-backup --compress --backup
    --compress-chunk-size=#
    mariadb-backup --backup --compress \
         --compress-threads=12 --compress-chunk-size=5M
    --compress-threads=#
    mariadb-backup --compress --compress-threads=12 --backup
    mariadb-backup --copy-back --force-non-empty-directories
    mariadb-backup --core-file --backup
    --databases="database[.table][ database[.table] ...]"
    mariadb-backup --backup \
          --databases="example.table1 example.table2"
    --databases-exclude="database[.table][ database[.table] ...]"
    mariadb-backup --backup \
          --databases="example" \
          --databases-exclude="example.table1 example.table2"
    --databases-file="/path/to/database-file"
    database[.table]
    cat main-backup
    example1
    example2.table1
    example2.table2
    mariadb-backup --backup --databases-file=main-backup
    --datadir=PATH
    mariadb-backup --backup -h /var/lib64/mysql
    mariadb-backup --compress --backup
    mariadb-backup --decompress
    --defaults-extra-file=/path/to/config
    mariadb-backup --backup \
          --defaults-file-extra=addition-config.cnf \
          --defaults-file=config.cnf
    --defaults-file=/path/to/config
    mariadb-backup --backup \
         --defaults-file=config.cnf
    --defaults-group="name"
    [mariadb-backup]
    compress_threads = 12
    compress_chunk_size = 64K
    mariadb-backup --compress --backup
    mariadb-backup --prepare --export
    --extra-lsndir=PATH
    mariadb-backup --extra-lsndir=extras/ --backup
    mariadb-backup --force-non-empty-directories --copy-back
    --ftwrl-wait-query-type=[ALL | UPDATE | SELECT]

    ALL

    Waits until all queries complete before issuing the global lock

    SELECT

    Waits until SELECT statements complete before issuing the global lock

    UPDATE

    Waits until UPDATE statements complete before issuing the global lock

    mariadb-backup --backup  \
          --ftwrl-wait-query-type=UPDATE
    --ftwrl-wait-threshold=#
    mariadb-backup --backup \
         --ftwrl-wait-timeout=90 \
         --ftwrl-wait-threshold=30
    --ftwrl-wait-timeout=#
    mariadb-backup --backup \
          --ftwrl-wait-query-type=UPDATE \
          --ftwrl-wait-timeout=5
    Unable to obtain lock. Please try again later.
    FATAL ERROR: failed to execute query BACKUP STAGE START:
    Lock wait timeout exceeded; try restarting transaction
    [00] 2022-02-08 15:43:25 Unable to obtain lock. Please try again later.
    [00] 2022-02-08 15:43:25 Error on BACKUP STAGE START query execution
    mariabackup: Stopping log copying thread.
    mariadb-backup --backup --galera-info
    --history[=name]
    mariadb-backup --backup --history=backup_all
    --host=name_or_ip-address
    mariadb-backup --backup \
          --host="192.168.0.33"
    mariadb-backup --innobackupex --incremental
    mariadb-backup --innobackupex --backup --incremental \
         --incremental-basedir=/data/backups \
         --target-dir=/data/backups
    --incremental-basedir=PATH
    mariadb-backup --backup \
         --incremental-basedir=/data/backups \
         --target-dir=/data/backups
    --increment-dir=PATH
    mariadb-backup --prepare \
          --increment-dir=backups/
    mariadb-backup --backup \
         --incremental-basedir=/path/to/target \
         --incremental-force-scan
    --incremental-history-name=name
    mariadb-backup --backup \
         --incremental-history-name=morning_backup
    --incremental-history-uuid=name
    mariadb-backup --backup \
          --incremental-history-uuid=main-backup012345678
    --incremental-lsn=name
    mariadb-backup --innobackupex
    mariadb-backup --backup \
          --innodb-adaptive-hash-index
    --innodb-autoextend-increment=36
    mariadb-backup --backup \
         --innodb-autoextend-increment=35
    --innodb-buffer-pool-size=124M
    mariadb-backup --backup \
          --innodb-buffer-pool-size=124M
    --innodb-data-file-path=/path/to/file
    mariadb-backup --backup \
         --innodb-data-file-path=ibdata1:13M:autoextend \
         --innodb-data-home-dir=/var/dbs/mysql/data
    --innodb-data-home-dir=PATH
    mariadb-backup --backup \
         --innodb-data-file-path=ibdata1:13M:autoextend \
         --innodb-data-home-dir=/var/dbs/mysql/data
    mariadb-backup --backup \
         --innodb-doublewrite
    --innodb-file-io-threads=#
    mariadb-backup --backup \
         --innodb-file-io-threads=5
    --innodb-flush-method=fdatasync 
                         | O_DSYNC 
                         | O_DIRECT 
                         | O_DIRECT_NO_FSYNC 
                         | ALL_O_DIRECT
    mariadb-backup --backup \
          --innodb-flush-method==_DIRECT_NO_FSYNC
    --innodb-io-capacity=#
    mariadb-backup --backup \
         --innodb-io-capacity=200
    mariadb-backup --backup \
          --innodb-log-checksums
    mariadb-backup --backup \
          --innodb-log-checkpoint-now
    --innodb-log-group-home-dir=PATH
    mariadb-backup --backup \
         --innodb-log-group-home-dir=/path/to/logs
    --innodb-max-dirty-pages-pct=#
    mariadb-backup --backup \
         --innodb-max-dirty-pages-pct=80
    --innodb-open-files=#
    mariadb-backup --backup \
          --innodb-open-files=10
    --innodb-page-size=#
    mariadb-backup --backup \
         --innodb-page-size=16k
    --innodb-read-io-threads=#
    mariadb-backup --backup \
          --innodb-read-io-threads=4
    --innodb-undo-directory=PATH
    mariadb-backup --backup \
         --innodb-undo-directory=/path/to/innodb_undo
    --innodb-undo-tablespaces=#
    mariadb-backup --backup \
          --innodb-undo-tablespaces=10
    mariadb-backup --backup \
          --innodb-use-native-aio
    --innodb-write-io-threads=#
    mariadb-backup --backup \
         --innodb-write-io-threads=4
    --kill-long-queries-timeout=#
    mariadb-backup --backup \
          --kill-long-queries-timeout=10
    --kill-long-query-type=ALL | UPDATE | SELECT
    mariadb-backup --backup \
          --kill-long-query-type=UPDATE
    --log-bin[=name]
    --log-copy-interval=#
    mariadb-backup --backup \
          --log-copy-interval=50
    mariadb-backup --move-back \
          --datadir=/var/mysql
    mariadb-backup --backup --no-backup-locks
    mariadb-backup --backup --no-lock
    mariadb-backup --backup --no-version-check
    --open-files-limit=#
    mariadb-backup --backup \
          --open-files-limit=
    --parallel=#
    --password=passwd
    mariadb-backup --backup \
          --user=root \
          --password=root_password
    --plugin-dir=PATH
    mariadb-backup --backup \
          --plugin-dir=/var/mysql/lib/plugin
    --port=#
    mariadb-backup --backup \
          --host=192.168.11.1 \
          --port=3306
    mariadb-backup --prepare
    mariadb-backup --print-defaults
    mariadb-backup --print-param
    mariadb-backup --backup --rsync
    mariadb-backup --backup \
          --safe-slave-backup \
          --safe-slave-backup-timeout=500
    --safe-slave-backup-timeout=#
    mariadb-backup --backup \
          --safe-slave-backup \
          --safe-slave-backup-timeout=500
    mariadb-backup --backup --secure-auth
    mariadb-backup --backup \
          --skip-innodb-adaptive-hash-index
    mariadb-backup --backup \
         --skip-innodb-doublewrite
    mariadb-backup --backup --skip-secure-auth
    mariadb-backup --slave-info
    --socket=name
    mariadb-backup --backup \
          --socket=/var/mysql/mysql.sock
    --ssl-ca=/etc/my.cnf.d/certificates/ca.pem
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem
    --ssl-capath=/etc/my.cnf.d/certificates/ca/
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem \
       --ssl-capath=/etc/my.cnf.d/certificates/ca/
    --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem
    --ssl-cipher=name
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem \
       --ssl-cipher=TLSv1.2
    --ssl-crl=/etc/my.cnf.d/certificates/crl.pem
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem \
       --ssl-crl=/etc/my.cnf.d/certificates/crl.pem
    --ssl-crlpath=/etc/my.cnf.d/certificates/crl/
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem \
       --ssl-crlpath=/etc/my.cnf.d/certificates/crl/
    --ssl-key=/etc/my.cnf.d/certificates/client-key.pem
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem \
       --ssl-verify-server-cert
    --stream=xbstream
    mariadb-backup --stream=xbstream > backup.xb
    mbstream  -x < backup.xb
    --tables=REGEX
    mariadb-backup --backup \
         --databases=example \
         --tables=nodes_* \
         --tables-exclude=nodes_tmp
    mariadb-backup --backup \
         --databases=example \
         --tables=^nodes. \
         --tables-exclude=^nodes_tmp.
    mariadb-backup --backup \
         --tables=test1[.].*,test2[.].* \
         --tables-exclude=^test2[.]exclude_table
         --target-dir=/path/to/backups/
    --tables-exclude=REGEX
    --tables-file=/path/to/file
    mariadb-backup --backup \
         --databases=example \
         --tables-file=/etc/mysql/backup-file
    --target-dir=/path/to/target
    mariadb-backup --backup \
           --target-dir=/data/backups
    --throttle=#
    --tls-version="TLSv1.2,TLSv1.3"
    mariadb-backup --backup \
       --ssl-cert=/etc/my.cnf.d/certificates/client-cert.pem \
       --ssl-key=/etc/my.cnf.d/certificates/client-key.pem \
       --ssl-ca=/etc/my.cnf.d/certificates/ca.pem \
       --tls-version="TLSv1.2,TLSv1.3"
    --tmpdir=/path/tmp[;/path/tmp...]
    mariadb-backup --backup \
         --tmpdir=/data/tmp;/tmp
    --use-memory=124M
    mariadb-backup --prepare \
          --use-memory=124M
    --user=name
    -u name
    mariadb-backup --backup \
          --user=root \
          --password=root_passwd
    mariadb-backup --verbose
    mariadb-backup --version

    Common Command Patterns

    Related Pages

    Options

    --apply-log

    --apply-log-only

    Note: This option is not needed or supported anymore.

    --backup

    --binlog-info

    --close-files

    --compress

    This option was deprecated as it relies on the no longer maintained QuickLZ library. It are removed in a future release - versions supporting this function will not be affected. It is recommended to instead backup to a stream (stdout), and use a 3rd party compression library to compress the stream, as described in Using Encryption and Compression Tools With mariadb-backup.

    --compress-chunk-size

    Deprecated, for details see the --compress option.

    --compress-threads

    Deprecated, for details see the --compress option.

    --copy-back

    --core-file

    --databases

    --databases-exclude

    --databases-file

    -h, --datadir

    --debug-sleep-before-unlock

    --decompress

    --debug-sync

    --defaults-extra-file

    --defaults-file

    --defaults-group

    --encrypted-backup

    --export

    --extra-lsndir

    --force-non-empty-directories

    --ftwrl-wait-query-type

    --ftwrl-wait-threshold

    --ftwrl-wait-timeout

    --galera-info

    --history

    -H, --host

    The mariadb-backup client cannot create backups from a remote server. Therefore, this option does not allow you to back up a remote server. mariadb-backup must always be run on the same server where the database files reside. The --host option is used only to establish the client connection for managing locks and retrieving metadata. The actual data files are always read from the local filesystem. Attempting to use this option to back up a remote host results in a backup of the local machine's data, associated with the remote machine's binary log coordinates.

    --include

    --incremental

    --incremental-basedir

    --incremental-dir

    --incremental-force-scan

    --incremental-history-name

    --incremental-history-uuid

    --incremental-lsn

    Incorrect LSN values can make the backup unusable. It is impossible to diagnose this issue.

    --innobackupex

    Deprecated option.

    --innodb

    --innodb-adaptive-hash-index

    --innodb-autoextend-increment

    --innodb-buffer-pool-filename

    --innodb-buffer-pool-size

    --innodb-checksum-algorithm

    --innodb-data-file-path

    --innodb-data-home-dir

    --innodb-doublewrite

    --innodb-encrypt-log

    --innodb-file-io-threads

    --innodb-file-per-table

    --innodb-flush-method

    --innodb-io-capacity

    --innodb-log-buffer-size

    --innodb-log-checksums

    --innodb-log-checkpoint-now

    --innodb-log-file-mmap

    This variable is available from MariaDB 11.4.4 and 10.11.10.

    --innodb-log-files-in-group

    --innodb-log-group-home-dir

    --innodb-max-dirty-pages-pct

    --innodb-open-files

    --innodb-page-size

    --innodb-read-io-threads

    --innodb-undo-directory

    --innodb-undo-tablespaces

    --innodb-use-native-aio

    --innodb-write-io-threads

    --kill-long-queries-timeout

    --kill-long-query-type

    --lock-ddl-per-table

    Unless the --no-lock option is also specified, conflicting DDL queries are killed at the end of backup This is done to avoid a deadlock between FLUSH TABLE WITH READ LOCK, user's DDL query (ALTER, RENAME), and MDL lock on table.

    --log

    --log-bin

    --log-copy-interval

    --log-innodb-page-corruption

    --move-back

    --mysqld

    --no-backup-locks

    --no-lock

    --no-timestamp

    --no-version-check

    --open-files-limit

    --parallel

    -p, --password

    --plugin-dir

    --plugin-load

    -P, --port

    --prepare

    --print-defaults

    --print-param

    --rollback-xa

    --rsync

    --safe-slave-backup

    --safe-slave-backup-timeout

    --secure-auth

    --skip-innodb-adaptive-hash-index

    --skip-innodb-doublewrite

    --skip-innodb-log-checksums

    --skip-secure-auth

    --slave-info

    -S, --socket

    --ssl

    --ssl-ca

    --ssl-capath

    --ssl-cert

    --ssl-cipher

    --ssl-crl

    --ssl-crlpath

    --ssl-key

    --ssl-verify-server-cert

    --stream

    --tables

    The --databases and --databases-exclude options, if used, take precedence over --tables and --tables-exclude. That is, they can filter out tables, which are then not "visible" to the latter mentioned options.

    --tables-exclude

    See the --tables option for examples and hints regarding regular expressions.

    --tables-file

    --target-dir

    --throttle

    --tls-version

    -t, --tmpdir

    --use-memory

    --user

    --verbose

    --version

    --prepare
    --apply-log
    --copy-back
    --move-back
    --incremental-basedir
    --incremental-dir
    --slave-info
    --binlog-info
    --galera-info
    --stream
    --extra-lsndir
    mariadb-backup Overview
    Full Backup and Restore (mariadb-backup)
    Incremental Backup and Restore (mariadb-backup)
    Using Encryption and Compression Tools With mariadb-backup
    --innobackupex
    --backup
    --prepare
    --incremental-dir
    --copy-back
    --move-back
    --target-dir
    --incremental-basedir
    --copy-back
    --move-back
    Full Backup and Restore
    Incremental Backup and Restore
    xtrabackup_binlog_pos_innodb
    xtrabackup_info
    --compress
    --compress-threads
    --compress
    --compress-chunk-size
    --databases-file option
    mariadb-backup Overview: Server Option Groups
    mariadb-backup Overview: Client Option Groups
    MDEV-13466
    mariadb_backup_info
    MDEV-18985
    MDEV-19246
    Storage I/O: Buffering and Persistence
    MDEV-32932
    MDEV-32932
    MDEV-19264
    openssl rehash
    openssl rehash
    spinner
    wsrep_local_state_uuid
    wsrep_last_committed
    --history[=name]
    mariadb-backup --backup --history=backup_all

    Replicas will, by default, use CREATE OR REPLACE when replicating CREATE statements that don't use IF EXISTS. This can be changed by setting the variable slave-ddl-exec-mode to STRICT.

    Changes to temporary tables are only binlogged if and only if the CREATE was logged. The logging happens under STATEMENT or MIXED. If binlog_format=ROW, temporary table changes are not binlogged. A temporary table that is changed under ROW is marked as 'not up to date in binlog' and no future row changes are logged. Any usage of this temporary table will force row logging of other tables in any future statements using the temporary table to be row logged.

  • DROP TEMPORARY is binlogged only if the CREATE was binlogged.

  • In some contexts, temporary tables on the primary and replica can become inconsistent. One example is if a temporary table is updated with the value of a non deterministic function like UUID(), in which the change is never sent to the replica.

    In some other contexts, while using MIXED mode, all changes will be logged in ROW mode while the user has any active temporary tables, even if the temporary tables are not used in the query. This depends on in which format some previous independent commands were logged.

    There are many other pitfalls with logging temporary table to the replica.

    : The delete/update operation is performed in both tables.
  • SET NULL: The update or delete goes ahead in the parent table, and the corresponding foreign key fields in the child table are set to NULL. (They must not be defined as NOT NULL for this to succeed).

  • SET DEFAULT: This option is currently implemented only for the PBXT storage engine, which is disabled by default and no longer maintained. It sets the child table's foreign key fields to their DEFAULT values when the referenced parent table key entries are updated or deleted.

  • FOR_EQUAL_HASH_POINT_TO_LAST_RECORD

    DEFAULT, YES, NO

    For a set of records that share the same hash value, controls which record the hash entry points to: NO points to the first record, YES points to the last.

    HASH
    indexes can only be used for =, <=, and >= comparisons. It can not be used for the
    ORDER BY
    clause. Searches against an index prefix are not possible.
  • RTREE is the default for SPATIAL indexes, but if the storage engine does not support it BTREE can be used.

  • ,
    ,
    ). From
    , not only ascending, but also descending, indexes can now be used to optimize
    and
    (
    ).

    NO — never use the adaptive hash index for this table, even when it is enabled at the server level.

    DYNAMIC.

    operator.
    VALUES IN
    is not allowed with
    RANGE
    . The partition function can be any valid SQL expression which returns a single value.
  • LIST assigns partitions based on a table's column with a restricted set of possible values. It is similar to RANGE, but VALUES IN must be used for at least 1 columns, and VALUES LESS THAN is disallowed.

  • SYSTEM_TIME partitioning is used for System-versioned tables to store historical data separately from current data.

  • How to create an index (name) that is only partly indexed (to save space).

    SHOW CREATE TABLE

  • CREATE TABLE with Vectors

  • Storage engines can add their own attributes for columns, indexes and tables

  • Variable slave-ddl-exec-mode

  • InnoDB Limitations

  • CREATE OR REPLACE TABLE table_name (a INT);
    DROP TABLE IF EXISTS TABLE_NAME;
    CREATE TABLE TABLE_NAME (a INT);
    CREATE VIEW v (mycol) AS SELECT 'abc';
    
    CREATE TABLE v2 LIKE v;
    ERROR 1347 (HY000): 'test.v' is not of type 'BASE TABLE'
    CREATE OR REPLACE TABLE x (d DATE DEFAULT '0000-00-00');
    
    SET SQL_MODE='NO_ZERO_DATE';
    
    CREATE OR REPLACE TABLE y LIKE x;
    ERROR 1067 (42000): Invalid default value for 'd'
    CREATE TABLE test (a INT NOT NULL, b CHAR(10)) ENGINE=MyISAM
        SELECT 5 AS b, c, d FROM another_table;
    ERROR 1050 (42S01): Table 't' already exists
    create_definition:
      { col_name column_definition | index_definition | period_definition | CHECK (expr) }
    
    column_definition:
      data_type
        [NOT NULL | NULL] [DEFAULT default_value | (expression)]
        [ON UPDATE [NOW | CURRENT_TIMESTAMP] [(precision)]]
        [AUTO_INCREMENT] [ZEROFILL] [UNIQUE [KEY] | [PRIMARY] KEY]
        [INVISIBLE] [{WITH|WITHOUT} SYSTEM VERSIONING]
        [COMMENT 'string'] [REF_SYSTEM_ID = value]
        [reference_definition]
      | data_type [GENERATED ALWAYS] 
      AS [ ROW {START|END} [NOT NULL ENABLE] [[PRIMARY] KEY]
            | (expression) [VIRTUAL | PERSISTENT | STORED] ]
          [INVISIBLE] [UNIQUE [KEY]] [COMMENT 'string']
    
    constraint_definition:
       CONSTRAINT [constraint_name] CHECK (expression)
    CREATE TABLE b(for_key INT REFERENCES a(not_key));
    CREATE TABLE b(for_key INT REFERENCES a(not_key));
    CREATE TABLE t1 (a INT DEFAULT (1+1), b INT DEFAULT (a+1));
    CREATE TABLE t2 (a BIGINT PRIMARY KEY DEFAULT UUID_SHORT());
    ### INSERT INTO `securedb`.`t_long_keys`
    ### SET
    ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
    ###   @2='a' /* VARSTRING(4073) meta=4073 nullable=1 is_null=0 */
    ###   @3=580 /* LONGINT meta=0 nullable=1 is_null=0 */
    CREATE TABLE t_long_keys (   a INT PRIMARY KEY,   b  VARCHAR(4073),   UNIQUE KEY `uk_b` (b) ) ENGINE=InnoDB;
    Query OK, 0 rows affected (0.022 sec)
    
    show create table t_long_keys\G
    *************************** 1. row ***************************
           Table: t_long_keys
    Create Table: CREATE TABLE `t_long_keys` (
      `a` int(11) NOT NULL,
      `b` varchar(4073) DEFAULT NULL,
      PRIMARY KEY (`a`),
      UNIQUE KEY `uk_b` (`b`) USING HASH
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
    1 row in set (0.001 sec)
    
    select * from information_schema.INNODB_SYS_TABLES where name like '%t_long_keys%';;
    +----------+----------------------+------+--------+-------+------------+---------------+------------+
    | TABLE_ID | NAME                 | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
    +----------+----------------------+------+--------+-------+------------+---------------+------------+
    |       64 | securedb/t_long_keys |   33 |      5 |    43 | Dynamic    |             0 | Single     |
    +----------+----------------------+------+--------+-------+------------+---------------+------------+
    1 row in set (0.003 sec)
    
    
    
    select * from information_schema.INNODB_SYS_COLUMNS where TABLE_ID=64;
    +----------+---------------+-------+-------+--------+------+
    | TABLE_ID | NAME          | POS   | MTYPE | PRTYPE | LEN  |
    +----------+---------------+-------+-------+--------+------+
    |       64 | a             |     0 |     6 |   1283 |    4 |
    |       64 | b             |     1 |     1 | 528399 | 4073 |
    |       64 | DB_ROW_HASH_1 | 65538 |     6 |   9736 |    8 |
    +----------+---------------+-------+-------+--------+------+
    
    CREATE TABLE t1(g GEOMETRY(9,4) REF_SYSTEM_ID=101);
    index_definition:
        {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ...
      {{{|}}} {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ...
      {{{|}}} [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ...
      {{{|}}} [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ...
      {{{|}}} [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition
    
    index_col_name:
        col_name [(length)] [ASC | DESC]
    
    index_type:
        USING {BTREE | HASH | RTREE}
    
    index_option:
        [ KEY_BLOCK_SIZE [=] value
      {{{|}}} index_type
      {{{|}}} WITH PARSER parser_name
      {{{|}}} VISIBLE
      {{{|}}} COMMENT 'string'
      {{{|}}} CLUSTERING={YES| NO}
      {{{|}}} ADAPTIVE_HASH_INDEX [=] {DEFAULT | YES | NO}
      {{{|}}} COMPLETE_FIELDS [=] number
      {{{|}}} BYTES_FROM_INCOMPLETE_FIELD [=] number
      {{{|}}} FOR_EQUAL_HASH_POINT_TO_LAST_RECORD [=] {DEFAULT | YES | NO} ]
      [ IGNORED | NOT IGNORED ]
    
    reference_definition:
        REFERENCES tbl_name (index_col_name,...)
          [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
          [ON DELETE reference_option]
          [ON UPDATE reference_option]
    
    reference_option:
        RESTRICT | CASCADE | SET NULL | NO ACTION

    COMPLETE_FIELDS

    0 to the number of columns the index is defined on (maximum 64)

    Number of complete index columns to include in the hash.

    BYTES_FROM_INCOMPLETE_FIELD

    0 to 16383

    Number of leading bytes to take from the next column, beyond those covered by COMPLETE_FIELDS. Only meaningful for memcmp()-comparable index fields such as VARBINARY or integer types. For example, a 3-byte prefix on an INT returns one hash value for 0‥255, another for 256‥511, and so on.

    period_definition:
        PERIOD FOR [time_period_name | SYSTEM_TIME] (start_column_name, end_column_name)
    CREATE TABLE t1 (a INT CHECK(a>0) ,b INT CHECK (b> 0), CONSTRAINT abc CHECK (a>b));
    <OPTION_NAME> = <option_value>, [<OPTION_NAME> = <option_value> ...]
    table_option:    
        [STORAGE] ENGINE [=] engine_name
      | ADAPTIVE_HASH_INDEX [=] {DEFAULT | YES | NO}
      | AUTO_INCREMENT [=] number
      | AVG_ROW_LENGTH [=] number
      | [DEFAULT] CHARACTER SET [=] <a data-footnote-ref href="#user-content-fn-7">charset_name</a>
      | CHECKSUM [=] {0 | 1}
      | [DEFAULT] COLLATE [=] <a data-footnote-ref href="#user-content-fn-7">collation_name</a>
      | COMMENT [=] 'string'
      | CONNECTION [=] 'connect_string'
      | DATA DIRECTORY [=] 'absolute path to directory'
      | DELAY_KEY_WRITE [=] {0 | 1}
      | ENCRYPTED [=] {YES | NO}
      | ENCRYPTION_KEY_ID [=] number
      | IETF_QUOTES [=] {YES | NO}
      | INDEX DIRECTORY [=] 'absolute path to directory'
      | INSERT_METHOD [=] { NO | FIRST | LAST }
      | KEY_BLOCK_SIZE [=] number
      | MAX_ROWS [=] number
      | MIN_ROWS [=] number
      | PACK_KEYS [=] {0 | 1 | DEFAULT}
      | PAGE_CHECKSUM [=] {0 | 1}
      | PAGE_COMPRESSED [=] {0 | 1}
      | PAGE_COMPRESSION_LEVEL [=] {0 .. 9}
      | PASSWORD [=] 'string'
      | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT|PAGE}
      | SEQUENCE [=] {0|1}
      | STATS_AUTO_RECALC [=] {DEFAULT|0|1}
      | STATS_PERSISTENT [=] {DEFAULT|0|1}
      | STATS_SAMPLE_PAGES [=] {DEFAULT|number}
      | TABLESPACE tablespace_name
      | TRANSACTIONAL [=]  {0 | 1}
      | UNION [=] (tbl_name[,tbl_name]...)
      | WITH SYSTEM VERSIONING
    partition_options:
        PARTITION BY
            { [LINEAR] HASH(expr)
            | [LINEAR] KEY(column_list)
            | RANGE(expr)
            | LIST(expr)
            | SYSTEM_TIME [INTERVAL time_quantity <a data-footnote-ref href="#user-content-fn-8">time_unit</a>] [LIMIT num] }
        [PARTITIONS num]
        [SUBPARTITION BY
            { [LINEAR] HASH(expr)
            | [LINEAR] KEY(column_list) }
          [SUBPARTITIONS num]
        ]
        [(partition_definition [, partition_definition] ...)]
    
    
    partition_definition:
        [PARTITION] partition_name
            [VALUES {LESS THAN {(expr) | MAXVALUE} | IN (value_list)}]
            [[STORAGE] ENGINE [=] engine_name]
            [COMMENT [=] 'comment_text' ]
            [DATA DIRECTORY [=] 'data_dir']
            [INDEX DIRECTORY [=] 'index_dir']
            [MAX_ROWS [=] max_number_of_rows]
            [MIN_ROWS [=] min_number_of_rows]
            [TABLESPACE [=] tablespace_name]
            [NODEGROUP [=] node_group_id]
            [(subpartition_definition [, subpartition_definition] ...)]
    
    
    subpartition_definition:
        SUBPARTITION logical_name
            [[STORAGE] ENGINE [=] engine_name]
            [COMMENT [=] 'comment_text' ]
            [DATA DIRECTORY [=] 'data_dir']
            [INDEX DIRECTORY [=] 'index_dir']
            [MAX_ROWS [=] max_number_of_rows]
            [MIN_ROWS [=] min_number_of_rows]
            [TABLESPACE [=] tablespace_name]
            [NODEGROUP [=] node_group_id]
    CREATE TABLE t1 (a INT, b CHAR(5), c DATETIME)
        PARTITION BY HASH ( YEAR(c) );
    CREATE OR REPLACE TABLE t1 (x INT)
      PARTITION BY RANGE(x) (
        PARTITION p1 VALUES LESS THAN (10),
        PARTITION p2 VALUES LESS THAN (20),
        PARTITION p3 VALUES LESS THAN (30),
        PARTITION p4 VALUES LESS THAN (40),
        PARTITION p5 VALUES LESS THAN (50),
        PARTITION pn VALUES LESS THAN MAXVALUE);
    CREATE OR REPLACE TABLE t1 (x INT)
      PARTITION BY RANGE(x) (
        p1 VALUES LESS THAN (10),
        p2 VALUES LESS THAN (20),
        p3 VALUES LESS THAN (30),
        p4 VALUES LESS THAN (40),
        p5 VALUES LESS THAN (50),
        pn VALUES LESS THAN MAXVALUE);
    CREATE OR REPLACE TABLE t1 (x INT)
      PARTITION BY RANGE(x) (
        PARTITION p1 VALUES LESS THAN (10),
        PARTITION p2 VALUES LESS THAN (20),
        PARTITION p3 VALUES LESS THAN (30),
        PARTITION p4 VALUES LESS THAN (40),
        PARTITION p5 VALUES LESS THAN (50),
        PARTITION pn VALUES LESS THAN MAXVALUE);
    CREATE TABLE IF NOT EXISTS test (
    a BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(128) CHARSET utf8,
    KEY name (name(32))
    ) ENGINE=InnoDB DEFAULT CHARSET latin1;
    CREATE TABLE t1(
      a INT DEFAULT (1+1),
      b INT DEFAULT (a+1),
      expires DATETIME DEFAULT(NOW() + INTERVAL 1 YEAR),
      x BLOB DEFAULT USER()
    );

    If the default_storage_engine is set to ColumnStore, it needs to be set on all UMs. Otherwise, when the tables using the default engine are replicated across UMs, they will use the wrong engine. You should therefore not use this option as a session variable with ColumnStore.

    Privileges

    CREATE OR REPLACE

    Things to be Aware of With CREATE OR REPLACE

    CREATE TABLE IF NOT EXISTS

    CREATE TEMPORARY TABLE

    Replicating temporary tables

    CREATE TABLE ... LIKE

    CREATE TABLE ... SELECT

    Column Definitions

    Note:

    NULL and NOT NULL

    DEFAULT Column Option

    AUTO_INCREMENT Column Option

    ZEROFILL Column Option

    PRIMARY KEY Column Option

    UNIQUE KEY Column Option

    COMMENT Column Option

    REF_SYSTEM_ID

    Generated Columns

    COMPRESSED

    INVISIBLE

    WITH SYSTEM VERSIONING Column Option

    WITHOUT SYSTEM VERSIONING Column Option

    Index Definitions

    Index Categories

    Plain Indexes

    PRIMARY KEY

    UNIQUE

    Unique, if index type is not specified, is normally a BTREE index that can also be used by the optimizer to find rows. If the key is longer than the max key length for the used storage engine, a HASH key will be created. This enables MariaDB to enforce uniqueness for any type or number of columns.

    FOREIGN KEY

    FULLTEXT

    SPATIAL

    Index Options

    KEY_BLOCK_SIZE Index Option

    ADAPTIVE_HASH_INDEX Index Option

    Added in MariaDB 13.1.1 (MDEV-37070).

    Advanced Adaptive Hash Index Tuning Options

    Added in MariaDB 13.1.1 (MDEV-37070).

    These are power-user options and are not needed for typical workloads. They override InnoDB's internal heuristic, which is computed and then replaced by the values you supply. Because the three options work together, set all three to known-good values whenever you set even one of them — setting only one or two leaves the others to interact with the overridden heuristic and can produce unintended results.

    InnoDB does not expose the values its heuristic would otherwise compute, so suitable settings must be derived from prior knowledge of the data and confirmed through performance testing.

    Index Types

    WITH PARSER Index Option

    VISIBLE Index Option

    COMMENT Index Option

    CLUSTERING Index Option

    IGNORED / NOT IGNORED

    Periods

    Constraint Expressions

    Table Options

    [STORAGE] ENGINE

    ADAPTIVE_HASH_INDEX

    The ADAPTIVE_HASH_INDEX table and index options were added in MariaDB 13.1.1 (MDEV-37070).

    AUTO_INCREMENT

    AVG_ROW_LENGTH

    [DEFAULT] CHARACTER SET/CHARSET

    CHECKSUM/TABLE_CHECKSUM

    [DEFAULT] COLLATE

    COMMENT

    CONNECTION

    DATA DIRECTORY/INDEX DIRECTORY

    DELAY_KEY_WRITE

    ENCRYPTED

    ENCRYPTION_KEY_ID

    IETF_QUOTES

    INSERT_METHOD

    KEY_BLOCK_SIZE

    MIN_ROWS/MAX_ROWS

    PACK_KEYS

    PAGE_CHECKSUM

    PAGE_COMPRESSED

    PAGE_COMPRESSION_LEVEL

    PASSWORD

    RAID_TYPE

    ROW_FORMAT

    Supported MyISAM Row Formats

    Supported Aria Row Formats

    Supported InnoDB Row Formats

    Other Storage Engines and ROW_FORMAT

    SEQUENCE

    STATS_AUTO_RECALC

    STATS_PERSISTENT

    STATS_SAMPLE_PAGES

    TRANSACTIONAL

    UNION

    WITH SYSTEM VERSIONING

    Partitions

    Sequences

    Atomic DDL

    Examples

    See Also

    TEMPORARY
    Identifier Names
    Microsecond precision
    CREATE
    replication
    LOCK TABLES
    DROP TABLE
    CREATE TEMPORARY TABLES
    default_tmp_storage_engine
    ROCKSDB
    default_tmp_storage_engine
    ROCKSDB
    default_tmp_storage_engine
    STATEMENT binary log format
    create_tmp_table_binlog_formats
    views
    SQL_MODE
    CAST()
    IGNORE
    Concurrent inserts
    INSERT ... SELECT
    Foreign Keys examples
    Indexes
    Data Types
    NULL Values in MariaDB
    INSERT
    DEFAULT
    CURRENT_TIMESTAMP
    DATETIME
    replicated
    row mode
    stored functions
    subqueries
    BLOB
    TEXT
    NEXT VALUE FOR sequence
    AUTO_INCREMENT
    DEFAULT
    LAST_INSERT_ID
    AUTO_INCREMENT
    INSERT
    numeric
    UNION
    INTERSECT
    EXCEPT
    Index Definitions
    Index Definitions
    SHOW FULL COLUMNS
    DML query
    built-in functions
    user-defined functions (UDFs)
    Generated (Virtual and Persistent/Stored) Columns
    Storage-Engine Independent Column Compression
    Invisible Columns
    System-versioned tables
    System-versioned tables
    InnoDB Limitations
    Getting Started with Indexes: Plain Indexes
    Getting Started with Indexes: Primary Key
    Getting Started with Indexes: Unique Index
    Foreign Keys
    Full-Text Indexes
    SPATIAL INDEX
    KEY_BLOCK_SIZE
    InnoDB
    ROW_FORMAT
    InnoDB
    SHOW CREATE TABLE
    KEY_BLOCK_SIZE
    ADAPTIVE_HASH_INDEX
    InnoDB
    InnoDB
    InnoDB
    Storage Engine Index Types
    MDEV-13756
    MDEV-26938
    MDEV-26939
    MDEV-26996
    MIN()
    MAX()
    MDEV-27576
    MDEV-13756
    FULLTEXT
    SHOW CREATE TABLE
    TokuDB
    Ignored Indexes
    Ignored Indexes
    System-versioned tables
    Application-time-period tables
    Bitemporal Tables
    UDFs
    ALTER TABLE DROP constraint_name
    CONSTRAINT
    extend CREATE TABLE with new options
    SQL_MODE
    storage engine
    default_storage_engine
    mariadbd startup option
    InnoDB
    SQL MODE
    SHOW ENGINES
    InnoDB
    innodb_adaptive_hash_index
    InnoDB
    ADAPTIVE_HASH_INDEX Index Option
    AUTO_INCREMENT
    MyISAM
    Aria
    ROW_FORMAT
    JSON data type
    Setting Character Sets and Collations
    character sets
    CHECKSUM TABLE
    MyISAM
    Aria tables
    JSON data type
    Setting Character Sets and Collations
    collations
    Spider
    Spider
    CONNECT
    Federated or FederatedX table
    innodb_file_per_table
    ALTER TABLE
    partitioned
    --skip-symbolic-links startup option
    the --keep_files_on_create option
    SQL_MODE
    datadir
    InnoDB
    InnoDB Encryption
    MDEV-18049
    Data-at-Rest Encryption
    InnoDB
    InnoDB Encryption
    MDEV-18049
    Data-at-Rest Encryption
    CSV
    MERGE
    InnoDB
    ROW_FORMAT
    Aria
    InnoDB page compression
    InnoDB
    InnoDB page compression
    InnoDB
    PAGE_COMPRESSED
    MyISAM
    myisampack
    MyISAM Storage Formats
    Aria
    Aria Storage Formats
    InnoDB
    innodb_strict_mode
    innodb_strict_mode
    innodb_strict_mode
    InnoDB Storage Formats
    sequence
    ANALYZE TABLE
    innodb_stats_auto_recalc
    InnoDB Persistent Statistics
    ANALYZE TABLE
    innodb_stats_persistent
    InnoDB Persistent Statistics
    innodb_stats_sample_pages
    InnoDB Persistent Statistics
    Aria Storage Engine
    System-versioned tables
    partitioned
    HASH
    HASH
    KEY
    RANGE
    HASH
    KEY
    Partitioning Types Overview
    SEQUENCE
    CREATE SEQUENCE
    Sequence Overview
    Atomic DDL
    automatically generated
    character set
    Identifier Names
    ALTER TABLE
    DROP TABLE
    Character Sets and Collations
    fill_help_tables.sql
    spinner
    MDEV-26938
    MDEV-26939
    MDEV-26996
    MIN()
    MAX()
    MDEV-27576
    MariaDB 11.3.2
    Replication Compatibility
    MariaDB 5.1
    MariaDB 10.1
    ColumnStore
    ColumnStore
    10.6.1
    MariaDB 10.5
    ColumnStore
    ColumnStore
    ColumnStore
    MariaDB 11.8
    Oracle mode
    MariaDB 10.1.31
    MariaDB 10.2.13
    MariaDB 10.4.14
    MariaDB 10.5.4
    MariaDB 10.1.38
    MariaDB 10.2.22
    MariaDB 10.3.13
    MariaDB 10.1.38
    MariaDB 10.2.22
    MariaDB 10.3.13
    MariaDB 11.4
    MariaDB 10.11
    MariaDB 11.0
    MariaDB 10.11.8
    MariaDB 11.0.6
    MariaDB 11.1.5
    MariaDB 11.2.4
    10.5
    MariaDB 10.11.8
    MariaDB 11.0.6
    MariaDB 11.1.5
    MariaDB 11.2.4
    MariaDB 10.6.17
    MariaDB 10.11.7
    MariaDB 11.0.5
    MariaDB 11.1.4
    MariaDB 11.2.3
    MariaDB 11.3.2
    MariaDB 11.4.1
    MariaDB 10.8
    MariaDB 10.8
    MariaDB 11.4.0