Databases for Joomla
Every Joomla site keeps almost everything it knows inside a database: your articles, menus, users, settings, extensions, and the long history of changes behind them. The pages a visitor sees are built fresh on each request by reading rows out of that database. So while the database is the part of Joomla you never look at directly, it is the part that holds the whole site together. Choose the right engine and keep it healthy, and your site stays fast and reliable. Neglect it, and you get slow pages, strange errors, and backups that do not restore.
This article explains the databases that run Joomla: MariaDB and MySQL, PostgreSQL, and the lesser-known SQLite and Microsoft SQL Server. It covers the basics for site owners, the connection and maintenance details for administrators, and the technical layer developers work with, including the table prefix, character sets, the query builder, and schema updates.
Joomla writes the pages, but the database remembers everything.
The goal is simple: help you understand which database suits your Joomla site and how Joomla talks to it.
1. The Basics
1.1 What is a Database?
A database is an organised store of information that other programs can read from and write to quickly. Joomla uses a relational database, which keeps data in tables. Each table has columns (the fields) and rows (the records). One article is one row in a table of articles; one user is one row in a table of users.
The software that manages these tables is the database engine (also called the database server or DBMS). Joomla does not store the data itself; it asks the engine to do it, using a language called SQL (Structured Query Language).
1.2 Why Joomla Needs One
A Joomla page is not a file on disk. When a visitor opens an article, Joomla runs PHP that sends an SQL query to the database, reads the result, and builds the HTML on the fly. Almost everything you manage in the backend lives in the database:
- Content: articles, categories, tags, contacts, and custom fields.
- Structure: menus, modules, and their positions.
- People: users, groups, and access levels.
- Configuration: most extension settings and the list of installed extensions.
A small number of things live as files instead, for example media uploads, the configuration.php file, and template code. Everything else is in the database.
1.3 Where the Database Lives
The database engine usually runs on the same server as your site, or on a dedicated database server next to it. Joomla connects to it over a network socket using a host name, a user name, a password, and a database name. You set those four values once, during installation, and Joomla stores them in configuration.php.
2. The Database Engines Joomla Supports
2.1 Officially Supported Versus Available
Joomla is built on the joomla/database framework, which ships drivers for several engines. But there is a difference between an engine that has a driver and an engine the Joomla CMS officially supports for a full site. The CMS only ships its install and update schema for two families:
| Engine | Driver name in Joomla | CMS support |
|---|---|---|
| MySQL (via MySQLi) | mysqli |
Fully supported (default) |
| MySQL (via PDO) | pdomysql |
Fully supported |
| MariaDB | mysqli or pdomysql |
Fully supported |
| PostgreSQL | pgsql |
Supported |
| SQLite | sqlite |
Framework only, not for a CMS site |
| Microsoft SQL Server | sqlsrv |
Framework only, not for a CMS site |
| Azure SQL | sqlazure |
Framework only, not for a CMS site |
2.2 How to Tell the Difference
The proof is in the schema folder. Joomla ships its database update scripts in administrator/components/com_admin/sql/updates/, and that folder contains exactly two subfolders: mysql and postgresql. There is no SQLite or SQL Server schema, so although the drivers exist, you cannot run a normal Joomla site on them without writing that schema yourself.
2.3 Server Type Versus Driver
Joomla groups the drivers into a smaller set of server types. Both mysqli and pdomysql report the server type mysql; pgsql reports postgresql; the SQL Server drivers report mssql. Extensions check the server type, not the exact driver, so a query written for "mysql" works whether the site uses MySQLi or PDO MySQL.
3. MySQL and MariaDB
3.1 The Default Choice
The large majority of Joomla sites run on MySQL or MariaDB. These are the databases that come with almost every shared hosting account and every cPanel server, and they are what a fresh Joomla install expects. If you do nothing special, this is what you get.
3.2 MariaDB Is a MySQL Fork
MariaDB began as a community fork of MySQL after Oracle bought MySQL, and the original MySQL developers built it. For Joomla they are close to interchangeable: the same SQL, the same table layout, the same Joomla driver. Joomla detects which one it is talking to and adjusts a few details automatically. Many hosts now ship MariaDB by default and simply call it "MySQL".
3.3 MySQLi Versus PDO MySQL
Joomla offers two ways to connect to a MySQL or MariaDB database, and you pick one during installation:
| Option | PHP extension | When to use |
|---|---|---|
| MySQLi | mysqli |
The default and most common. Stable and well tested. |
| MySQL (PDO) | pdo_mysql |
Uses PHP's PDO layer. Choose it if your host or workflow prefers PDO. |
For nearly all sites the difference does not matter. MySQLi is the safe default. Both talk to the same database and store data in the same way, so you can move between them by changing one line in configuration.php, as long as the matching PHP extension is installed.
3.4 Minimum Versions
Joomla 6.x requires MySQL 8.0.13 or higher (recommended: MySQL 8.4), or MariaDB 10.4 or higher (recommended: MariaDB 12.0), see: Joomla! Programmers Documentation: Requirements for Joomla! 6.x. Older numbers you may see quoted (MySQL 5.6, MariaDB 10.0) are the floor of the underlying joomla/database library, not the requirement of the modern CMS; a Joomla 6 site will not run on them. Run a current, supported release for better speed, security, and full utf8mb4 support. A host still offering MySQL 5.7 or an old MariaDB is running software past its prime, and you should upgrade or move before installing Joomla 6.
4. PostgreSQL
4.1 A Supported Alternative
PostgreSQL (often shortened to "Postgres") is a powerful open-source relational database with a long reputation for correctness and standards compliance. Joomla supports it as a full alternative to MySQL and MariaDB: the CMS ships a complete PostgreSQL schema and update path, so you can install and run a real Joomla site on it.
4.2 Why You Might Choose It
People pick PostgreSQL when their organisation already standardises on it, when they need its advanced data types and strict data handling, or when a hosting platform offers it as the managed default. It is a mature, dependable engine.
4.3 The Honest Trade-Off
The catch is the extension ecosystem. The overwhelming majority of Joomla extensions are written and tested against MySQL or MariaDB. Many use MySQL-specific SQL and never get tested on PostgreSQL, so they can fail in subtle ways. Joomla core works well on PostgreSQL, but before you commit a production site to it, confirm that every third-party extension you depend on supports it. Joomla 6.x requires PostgreSQL 12.0 or higher (the old 9.x figure is only the underlying library's floor), so run a current major release.
Back to top5. SQLite and Microsoft SQL Server
5.1 SQLite: The File-Based Engine
SQLite is unusual: it is not a server at all. The whole database is a single file on disk, and the engine runs inside the application that opens it. There is nothing to install or connect to over a network, which makes it perfect for testing, automated test suites, and small embedded tools.
Joomla's framework ships an SQLite driver, and the Joomla project uses SQLite internally for some of its own automated tests. But the Joomla CMS does not ship an SQLite install schema, so you cannot run a normal Joomla website on it. Treat the SQLite driver as a developer and framework tool, not a hosting option.
5.2 Microsoft SQL Server and Azure SQL
The framework also ships drivers for Microsoft SQL Server (sqlsrv) and Azure SQL (sqlazure), both reported as the server type mssql. As with SQLite, the CMS has no MSSQL install or update schema, so these drivers exist for custom applications built on the Joomla framework, not for a standard Joomla site. If a host or article suggests installing Joomla on SQL Server, treat it with care: the supported path for a Microsoft environment is to run MySQL or MariaDB on Windows, or to use IIS in front of a MySQL database.
5.3 The Practical Takeaway
For a real Joomla website, your real choices are MySQL, MariaDB, or PostgreSQL. SQLite and SQL Server matter only if you are a developer building a custom application on top of the Joomla framework.
Back to top6. Choosing the Right Database
6.1 A Practical Comparison
For most people the choice is made for them by their host. When you do have a choice, these are the points that matter:
| Engine | Best for | Extension support | CMS install |
|---|---|---|---|
| MariaDB | Most sites; the modern default | Excellent | Yes |
| MySQL | Sites on hosts that ship Oracle MySQL | Excellent | Yes |
| PostgreSQL | Postgres-standard organisations | Limited (test first) | Yes |
| SQLite | Framework tests and tooling | Not applicable | No |
| MS SQL Server | Custom framework apps only | Not applicable | No |
6.2 A Simple Rule of Thumb
- For almost every Joomla site, choose MariaDB (or MySQL if that is what your host provides). The whole extension ecosystem is built and tested on it.
- Choose PostgreSQL only if you have a strong reason and you have checked that your extensions support it.
- Do not try to run a production Joomla site on SQLite or SQL Server.
The brand of database matters far less than keeping it on a current version, giving it enough memory, and backing it up. A well-tuned MariaDB beats a neglected anything.
Back to top7. How Joomla Connects to the Database
7.1 The configuration.php File
Joomla stores the database connection details in the root file configuration.php, set during installation. Five settings define the connection:
public $dbtype = 'mysqli'; // the driver: mysqli, pdomysql, or pgsql
public $host = 'localhost'; // database server address
public $user = 'joomla_user'; // database account
public $password = 'secret'; // its password
public $db = 'joomla_site'; // the database name
public $dbprefix = 'abcd1_'; // the table prefix (see section 8)
The $dbtype value is the driver name from section 2. To switch a MySQL site from MySQLi to PDO, you change mysqli to pdomysql here, provided the pdo_mysql PHP extension is installed. Because this file holds the password in plain text, the web server must never serve it; Joomla and a correct server configuration keep it private.
7.2 The Host Value
The $host is usually localhost or 127.0.0.1 when the database runs on the same machine. Managed and cloud hosting often gives you a separate host name and sometimes a port, written as host:port. Some setups connect over a Unix socket instead of TCP. Your host tells you the correct value; a wrong host is the most common cause of "Could not connect to the database" during install.
7.3 What Happens on Each Request
When a request arrives, Joomla reads configuration.php, loads the matching driver, and opens a connection to the engine. Every query in that request travels over that one connection, and Joomla closes it when the request ends. This is why a slow or overloaded database makes the whole site feel slow: every page waits on it.
7.4 Connecting to a Remote Database
When you develop locally but want to work against a database on a remote server, you have two ways to reach it, and they have very different security profiles.
Direct connection with an IP allowlist. You point Joomla straight at the remote server by setting $host to its address and port, for example db.example.com:3306. For this to work the remote database must accept outside connections, the firewall must allow your IP address, and the database user must be permitted to connect from it. This is simple, but it exposes the database port to the internet and breaks whenever your home or office IP changes.
SSH tunnel (the safer option). Instead of opening the database to the world, you forward a local port through SSH to the remote server. Joomla then connects to that local port as if the database were on your own machine. You open the tunnel with one command:
ssh -N -L 3307:127.0.0.1:3306 This email address is being protected from spambots. You need JavaScript enabled to view it.
This maps local port 3307 to 127.0.0.1:3306 as seen from the remote server, which is its own MySQL. Now point Joomla at the local end of the tunnel:
public $host = '127.0.0.1:3307'; // local end of the SSH tunnel
public $user = 'remote_db_user';
public $password = 'remote_db_password';
public $db = 'remote_db_name';
Because the tunnel ends on the remote server, MySQL sees the connection as coming from its own localhost, so the database account can stay restricted to localhost and the database port never needs to face the internet. Only SSH (key-authenticated) is exposed, which is why a tunnel is safer than opening the port and allowlisting an IP.
Two important details:
- Use
127.0.0.1, notlocalhost. The MySQLi driver treats the literal wordlocalhostas a request for a Unix socket and ignores the port, which bypasses the tunnel.127.0.0.1forces a real TCP connection to the forwarded port. - The SSH credentials are not in Joomla. The SSH host, user, and key live in your SSH client (the command above or an
~/.ssh/configentry), never inconfiguration.php. Joomla only ever sees the database connection to127.0.0.1:3307. These are two separate logins: SSH authenticates the tunnel, the database credentials authenticate Joomla.
Keep the tunnel open the whole time Joomla runs; if it drops, Joomla immediately reports "Could not connect to the database". A tool such as autossh reopens it automatically. Remember too that you are working on live data, so treat destructive actions with the same care as on production.
8. The Table Prefix and Schema
8.1 Why Tables Have a Prefix
Joomla does not name its tables content or users directly. Every table starts with a short prefix, for example abcd1_content or abcd1_users. The installer generates a random prefix (you can change it) and stores it as $dbprefix. The prefix does two useful things:
- It lets several applications share one database without their tables clashing.
- It makes blind attacks a little harder, because an attacker cannot guess your exact table names.
8.2 The #__ Placeholder
Inside Joomla code and SQL you never write the real prefix. You write the placeholder #__ (hash, underscore, underscore), and Joomla replaces it with the real prefix at query time. So this query:
SELECT * FROM #__content WHERE state = 1
becomes SELECT * FROM abcd1_content WHERE state = 1 before it reaches the database. This is why extension SQL and the documentation always refer to tables as #__content, #__users, #__menu, and so on. It keeps code portable across sites with different prefixes.
8.3 A Map of the Core Tables
A standard Joomla install creates dozens of tables. A few of the most important ones:
| Table | What it holds |
|---|---|
#__content |
Articles. |
#__categories |
Categories for all content types. |
#__users |
User accounts. |
#__user_usergroup_map |
Which users belong to which groups. |
#__menu |
Menu items and their routing. |
#__modules |
Modules and their settings. |
#__extensions |
Every installed extension and its parameters. |
#__fields / #__fields_values |
Custom fields and their stored values. |
#__assets |
The access-control (ACL) tree. |
You rarely touch these by hand. Joomla and its extensions read and write them through the database layer described next.
Back to top9. Character Sets and Collation
9.1 Why Encoding Matters
A character set decides which characters the database can store; a collation decides how it sorts and compares them. Get this wrong and accented letters, emoji, or non-Latin scripts turn into question marks or mojibake, and sorting goes strange. Joomla aims for full Unicode so a site can hold any language.
9.2 How Collation Changes Sorting
Collation is not only about storage; it decides the order of an alphabetical list, and that order depends on the language. The same words sort differently under a general (ASCII/English) collation than under a language-specific one. A classic example is the Swedish city Örebro:
- General (ASCII/English) collation:
Öis treated like a plainO, so "Örebro" is sorted as if it were "Orebro" and lands among the O entries. - Swedish collation:
Öis a separate letter that comes after Z. The Swedish alphabet ends with X, Y, Z, Å, Ä, Ö, so "Örebro" sorts near the very end of the list.
The effect on a list of city names is easy to see:
| General / English sorting | Swedish sorting |
|---|---|
| Malmö (treated as "Malmo") | Malmö |
| Örebro (treated as "Orebro") | Stockholm |
| Stockholm | Uppsala |
| Uppsala | Örebro |
This is why a multilingual Joomla site can show a category or tag list in an order that looks wrong to a native speaker: the database is sorting correctly, just under the wrong collation for that language. The fix is to match the collation to the content's language rather than leaving everything on a single general collation.
9.3 utf8mb4 on MySQL and MariaDB
On MySQL and MariaDB, Joomla uses utf8mb4, the four-byte UTF-8 encoding that can store every Unicode character, including emoji. The older utf8 in MySQL is really only three bytes and cannot store emoji or some Asian characters, which caused years of subtle bugs. Joomla checks the database version and switches utf8mb4 support on when the server is new enough (MySQL or MariaDB from the 5.5.3 generation onward). A typical Joomla table uses utf8mb4_unicode_ci collation, where ci means case-insensitive.
9.4 The Null Date Detail
Each engine represents an "empty" timestamp differently, and Joomla knows the right value per driver. On MySQL and MariaDB the historic null date is 0000-00-00 00:00:00; when the server runs in strict mode that forbids zero dates, Joomla uses 1000-01-01 00:00:00 instead. PostgreSQL uses 1970-01-01 00:00:00 and SQL Server uses 1900-01-01 00:00:00. This is invisible in daily use, but it explains why you should never hard-code 0000-00-00 in your own queries. Ask the driver for the null date instead, with $db->getNullDate().
Modern Joomla has moved away from the zero-date sentinel where it can. Many date columns are now nullable, and an empty date is stored as a real SQL NULL rather than 0000-00-00; a current Joomla 6 schema no longer defaults any column to a zero date. The null date returned by getNullDate() still matters for the columns that remain non-nullable, for example created on #__content. So the safe rule has two parts: compare against $db->getNullDate() for non-nullable date columns, and check for SQL NULL on the nullable ones, rather than ever writing 0000-00-00 by hand.
10. Under the Hood: Joomla's Database Layer
10.1 The Driver and the Interface
Joomla never lets your code talk to MySQL functions directly. Instead it gives you a database driver object that implements Joomla\Database\DatabaseInterface. Whatever engine sits underneath, your code uses the same methods, so the same PHP works on MySQL and PostgreSQL alike. You get the shared driver from the dependency container:
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseInterface;
$db = Factory::getContainer()->get(DatabaseInterface::class);
This single object is the door to the whole database. Older code used Factory::getDbo(); the container approach above is the modern, preferred way.
10.2 Running a Simple Query
Once you have the driver, you set a query and ask for the result in the shape you want:
$db->setQuery('SELECT title FROM #__content WHERE id = 42');
$title = $db->loadResult(); // a single value
$row = $db->loadObject(); // one row as an object
$rows = $db->loadObjectList(); // many rows
$column = $db->loadColumn(); // one column from many rows
The load* family hides the engine differences and gives you plain PHP values, objects, or arrays.
10.3 The Server Type Switch
When you must write engine-specific SQL, do not guess from the driver name. Ask for the server type and branch on it:
if ($db->getServerType() === 'postgresql') {
// PostgreSQL-specific SQL
} else {
// MySQL / MariaDB SQL
}
This is the same check Joomla core uses, and it keeps an extension working across both supported engines.
Back to top11. Writing Queries the Joomla Way
11.1 The Query Builder
Hand-written SQL strings are fragile and easy to get wrong, especially around quoting. Joomla provides a query builder that writes correct, portable SQL for the active engine. You get an empty query with $db->getQuery(true) and chain methods onto it:
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true);
$query->select($db->quoteName(['id', 'title']))
->from($db->quoteName('#__content'))
->where($db->quoteName('state') . ' = :state')
->order($db->quoteName('created') . ' DESC');
$query->bind(':state', 1, ParameterType::INTEGER);
$db->setQuery($query);
$articles = $db->loadObjectList();
11.2 Quote Names and Bind Values
Two rules keep your queries safe and portable:
- Quote identifiers (table and column names) with
$db->quoteName(). It adds the correct quote character for the engine, backticks on MySQL and double quotes on PostgreSQL. - Bind values with named parameters and
bind(), or quote them with$db->quote(). Never paste a raw value from a form straight into SQL.
11.3 Why This Stops SQL Injection
SQL injection is the attack where a user types SQL into a form field and the server runs it. Binding parameters defeats it, because a bound value is always treated as data, never as code. The query builder is not just tidy; it is the front line of Joomla's database security. Most data-breach reports in Joomla extensions trace back to a query that skipped this step.
Back to top12. Storage Engines, Transactions, and Integrity
12.1 The Storage Engine
On MySQL and MariaDB, the storage engine is the part of the database that actually stores the table data and decides how it is read, written, and locked. The choice matters, and Joomla makes it for you: core tables are created with ENGINE=InnoDB. Nearly all Joomla core tables use InnoDB. Some specialised or temporary tables created by Joomla or extensions may use the MEMORY engine, but this is uncommon.
| Feature | InnoDB | MyISAM (old) |
|---|---|---|
| Transactions | Yes | No |
| Locking | Row-level | Table-level |
| Crash recovery | Strong | Weak |
| Foreign keys | Supported | Not supported |
| Joomla use | All core tables | Legacy sites only |
The older MyISAM engine can be quick for pure reading, but it locks a whole table on every write and has no transactions and weak crash recovery. On a busy site that mixes reads and writes, table locking makes pages queue behind each other. If you inherit an old site whose tables are still MyISAM, convert them to InnoDB; it is a safe, well-trodden change.
12.2 Transactions and ACID
A transaction groups several queries so they either all succeed or all fail together. The classic example is an order: create the order, reduce the stock, record the payment. If the payment step fails, you do not want the stock already reduced. A transaction lets the database undo the earlier steps as if they never happened.
This is the idea behind ACID, the four guarantees a serious database makes: Atomicity (all or nothing), Consistency (the data stays valid), Isolation (concurrent transactions do not corrupt each other), and Durability (a committed change survives a crash). InnoDB is an ACID-compliant storage engine; MyISAM is not, which is another reason Joomla standardises on InnoDB.
Joomla's database layer exposes transactions through three methods on the driver:
$db->transactionStart();
try {
// several related queries that must succeed together
$db->setQuery($query1)->execute();
$db->setQuery($query2)->execute();
$db->transactionCommit();
} catch (\Exception $e) {
$db->transactionRollback();
throw $e;
}
Use a transaction whenever one logical change spans more than one table or row, so a half-finished operation cannot leave the database in a broken state.
12.3 Why Joomla Avoids Foreign Keys
A foreign key is a database rule that ties a column in one table to a row in another, for example linking an article's catid to a real row in #__categories. The database then refuses to store an article that points at a category which does not exist. InnoDB supports foreign keys, yet the Joomla core schema declares almost none of them. This surprises developers who come from other frameworks.
The reason is deliberate. Joomla enforces these relationships in PHP, in its models and table classes, rather than in the database. That keeps the schema portable across MySQL, MariaDB, and PostgreSQL, and it dates back to when MyISAM (which has no foreign keys) was the default. The practical consequence is important: because the database does not stop you, deleting or editing rows by hand can leave orphaned records, for example a module pointing at a menu item that no longer exists. For routine site administration, use the Joomla backend or Joomla's database API. Direct SQL updates should be reserved for administrators who understand the relationships between Joomla tables.
Back to top13. Schema Updates and Migrations
13.1 How Joomla Changes the Database
When Joomla or an extension updates, the new version often needs new columns or tables. Joomla applies these changes through versioned SQL update files. The core files live in administrator/components/com_admin/sql/updates/, split by engine into mysql/ and postgresql/ folders, with one file per change named by version and date.
13.2 The Database Fix Tool
Sometimes an update is interrupted, or a database drifts out of step with the version Joomla expects. Joomla has a built-in check at System → Maintenance → Database. It compares your actual schema to the schema the installed version should have and offers a Fix button that runs the missing changes. If you ever see "Database schema is not up to date", this is the page that repairs it.
13.3 The Command Line
The same maintenance exists on the command line, which is handy for scripted deployments:
php cli/joomla.php maintenance:database
This checks the schema and reports or fixes problems without opening the backend. It is the database equivalent of clearing a stuck update by hand.
13.4 Extensions Do the Same
Well-built extensions ship their own SQL update files and an install script, so installing a new version brings their tables up to date automatically. This is why you update extensions through the Joomla installer rather than copying files over the top: the installer runs the schema changes that loose files would skip.
Back to top14. Backups and Maintenance
14.1 A Backup Is a Database Backup
Because the site lives in the database, a backup that does not include the database is almost worthless. A complete Joomla backup has two parts: the files (media, templates, extensions, configuration.php) and a full SQL dump of the database. Tools like Akeeba Backup bundle both into one archive; a plain file copy alone will not restore your content.
14.2 Taking a Dump by Hand
On a server with shell access you export the database with the engine's own tool. For MySQL or MariaDB:
mysqldump -u USER -p DATABASE > backup.sql # export
mysql -u USER -p DATABASE < backup.sql # import
For PostgreSQL the equivalents are pg_dump and psql. Keep the export and the matching file copy together, and test a restore now and then; a backup you have never restored is only a hope.
14.3 Routine Maintenance
A few habits keep a Joomla database healthy:
- Clear old data Joomla lets pile up: action logs, expired sessions, and old content versions in
#__history. - Uninstall extensions you no longer use, so their tables do not linger.
- Keep the engine on a current, patched version.
- Watch the database size; runaway log or cache tables are the usual cause of sudden growth.
15. Performance and Tuning
15.1 Indexes Are the Big Lever
An index is a lookup structure that lets the database find rows without scanning the whole table, like the index at the back of a book. Joomla's core tables come well indexed. The performance problems people hit usually come from large custom tables or extensions that query unindexed columns. If a specific page is slow, the cause is often a query missing an index. Indexes are not free, though: each one speeds up reads but adds a little cost to every insert and update, so index the columns you search and filter on, not every column.
15.2 Find the Slow Queries
Turn on Joomla's Debug mode in Global Configuration and the Debug plugin shows every query a page ran, with timings. The database engine can also log slow queries (MySQL's slow query log). Together they tell you exactly which query to fix, instead of guessing.
15.3 Read the Query Plan with EXPLAIN
Once you know which query is slow, ask the database why. Every engine has a query planner that decides how to run a query, and you can see its plan by putting EXPLAIN in front of the query:
EXPLAIN SELECT title FROM #__content WHERE state = 1;
The output tells you whether the database uses an index or scans the whole table (look for "ALL", which means a full table scan). On PostgreSQL, EXPLAIN ANALYZE goes further and actually runs the query to report real timings. This is the single most useful habit for diagnosing a slow query: do not guess whether an index helps, measure it.
15.4 Caching Saves the Database
The fastest query is the one you never run. Joomla's caching (the System - Page Cache plugin and view caching) stores built pages and query results so repeat visits skip the database entirely. On a busy site this takes huge load off the engine. Pair it with a persistent cache store such as Redis or Memcached for the best effect.
15.5 Give the Engine Room
A database engine is far faster when it can hold the working data in memory. On a managed host this is tuned for you; on your own server, settings like MariaDB's innodb_buffer_pool_size decide how much of the database stays cached in RAM. Enough memory for the engine often does more for speed than any single Joomla setting.
15.6 A Real Example: Avoiding DISTINCT
One lesson from Joomla core development itself shows why the shape of a query matters more than the engine under it. When I developed the Category Item Count feature for Joomla in 2015, my first version used SQL's DISTINCT keyword to remove duplicate rows. On small sites it worked fine. But people with very large sites, many categories each holding a huge number of articles, reported serious slowdowns.
The reason is that DISTINCT forces the database to work out which rows are duplicates before it can return a result, often with extra sorting, a temporary table, or hashing. On a large dataset that becomes expensive. The query was later rewritten to produce the same result without DISTINCT, and the slowdown went away.
A query that looks elegant is not always the fastest query.
When you write SQL for a Joomla extension, and you reach for DISTINCT to hide duplicates, stop and ask where the duplicates come from. Often a better JOIN, a more selective WHERE, a GROUP BY, or one more index removes the need for it entirely. And always confirm with EXPLAIN (MySQL and MariaDB) or EXPLAIN ANALYZE (PostgreSQL) instead of assuming the query is already optimal.
16. SEO and Metadata
The database does not contain meta tags or sitemaps directly, but it shapes SEO in two quiet ways. First, it stores the data that SEO depends on: article metadata, the URL aliases in #__content and #__menu, and the redirect table #__redirect_links that turns broken links into clean 301s. Second, and more important, database speed feeds Core Web Vitals. A page that waits on a slow query is a slow page, and search engines measure that.
- Keep queries fast with indexes and caching so pages load quickly, which Google rewards.
- Keep the
#__redirect_linkstable in order so moved pages return 301 instead of 404. - Back up before bulk-editing aliases or categories; a botched mass change can break every URL on the site at once.
None of this needs an SEO extension. A healthy, fast database is itself an SEO asset because every page is built from it.
Back to top17. Common Mistakes and Pitfalls
17.1 Wrong Connection Details
Symptom: installation or the site fails with "Could not connect to the database".
Fix: check the four values in configuration.php against what your host gave you: host (often localhost or with a port), user, password, and database name. A wrong host or a database that does not exist yet is the usual cause.
17.2 Choosing PostgreSQL Without Checking Extensions
Symptom: core works, but a third-party extension throws SQL errors on PostgreSQL.
Fix: confirm every extension supports PostgreSQL before you commit. When in doubt, use MariaDB, which the whole ecosystem targets.
17.3 The utf8 Versus utf8mb4 Trap
Symptom: emoji or some characters save as question marks, or a migrated database shows mojibake.
Fix: make sure the database and tables use utf8mb4, not the old three-byte utf8. Convert an older database to utf8mb4 rather than leaving it on utf8.
17.4 Editing Tables by Hand
Symptom: data looks fine in phpMyAdmin but Joomla behaves oddly, loses access rights, or shows orphaned items.
Fix: avoid direct table edits. Joomla keeps related tables in step (assets, history, associations); changing one row by hand can break those links. Use the backend or the database layer.
17.5 No Database in the Backup
Symptom: a "backup" restores the files but the site is empty or stuck on an old version.
Fix: always back up files and the SQL dump together, and test a restore. A file-only copy is not a Joomla backup.
17.6 Hard-Coding the Table Prefix
Symptom: custom SQL works on one site but fails on another with a different prefix.
Fix: write #__tablename, never the literal prefix. Joomla substitutes the real prefix at run time.
18. Best Practices
If you remember only a few things from this article, remember these:
- For almost every site, use MariaDB or MySQL; the whole extension ecosystem is built on it.
- Choose PostgreSQL only with a clear reason and after testing every extension.
- Do not run a production Joomla site on SQLite or SQL Server; their drivers are for framework apps, not the CMS.
- Keep the engine on a current, supported version and make sure it uses utf8mb4.
- Protect
configuration.php; it holds the database password in plain text. - In code, always use the database layer:
quoteName()for names and bound parameters for values, to stop SQL injection. - Write
#__instead of the real table prefix so your SQL stays portable. - Back up files and the SQL dump together, and test a restore regularly.
- Keep tables on InnoDB, and wrap multi-step changes in a transaction so they cannot half-finish.
- Use Debug mode, the slow query log, and
EXPLAINto find slow queries, then add indexes or caching. - Be wary of
DISTINCT; it often hides a query that a better JOIN, WHERE, GROUP BY, or index would solve faster. - Run the Database fix tool after any interrupted update.
19. Quick Reference
SUPPORTED (CMS) MariaDB, MySQL, PostgreSQL
DRIVER-ONLY SQLite, MS SQL Server, Azure SQL (framework apps)
DBTYPE VALUES mysqli, pdomysql, pgsql
SERVER TYPES mysql, postgresql, mssql, sqlite
REQUIREMENTS Joomla 6.x: MySQL 8.0.13+, MariaDB 10.4+, PostgreSQL 12.0+
CONNECTION configuration.php: dbtype, host, user, password, db, dbprefix
TABLE PREFIX Write #__table; Joomla swaps in the real prefix
ENCODING utf8mb4 on MySQL/MariaDB (not 3-byte utf8)
GET DRIVER Factory::getContainer()->get(DatabaseInterface::class)
QUERY $db->getQuery(true) + quoteName() + bind()
ENGINE CHECK $db->getServerType() // 'mysql' or 'postgresql'
STORAGE ENGINE InnoDB for all core tables (not MyISAM)
TRANSACTIONS $db->transactionStart() / transactionCommit() / Rollback()
INTEGRITY Joomla uses no DB foreign keys; enforced in PHP
SCHEMA FILES administrator/components/com_admin/sql/updates/{mysql,postgresql}
FIX SCHEMA System → Maintenance → Database (or CLI below)
CLI php cli/joomla.php maintenance:database
BACKUP Files + SQL dump together (mysqldump / pg_dump)
SPEED Indexes + caching (Page Cache, Redis) + engine memory
DIAGNOSE EXPLAIN (MySQL) / EXPLAIN ANALYZE (PostgreSQL); avoid DISTINCT
Back to top20. Summary
The database is where your Joomla site truly lives. Almost every article, menu, user, and setting is a row that Joomla reads to build each page, so the health of the database is the health of the site.
- MariaDB and MySQL are the default and the safe choice, supported by the whole extension ecosystem.
- PostgreSQL is a fully supported alternative, but only if your extensions support it too.
- SQLite and SQL Server have framework drivers but no CMS schema, so they are for custom applications, not websites.
- Joomla talks to all of them through one database layer, using the
#__prefix, the query builder, and bound parameters to stay portable and safe. - Good encoding, backups, indexes, and caching matter more than the brand of engine you pick.
If your Joomla site is slow, throws schema errors after an update, or saves the wrong characters, the cause is often in the database rather than in Joomla itself. A careful look at the version, the encoding, the slow queries, and the backups usually finds the problem, and it is exactly the kind of quiet, foundational work that keeps a site fast and dependable for years.
Back to top

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.
Frequently Asked Questions
Joomla uses MySQL or MariaDB as its primary database to store website content, user accounts, menus, extensions, settings, and configuration data. Joomla also supports PostgreSQL, although MySQL and MariaDB are the recommended and most widely used options for optimal compatibility and performance.
The Joomla database is stored on a database server, usually MySQL or MariaDB, not inside your website files. Joomla stores the database connection details, including the database name, username, password, host, and password, in the configuration.php file so it can access your site's content and settings.
Joomla stores its data across many database tables, each with a specific purpose. Every table name begins with a unique table prefix (shown as #__ in Joomla code, for example jos_ or a random prefix like abc12_). This prefix is configured in configuration.php and helps prevent conflicts and improves security when multiple Joomla installations share the same database. In Joomla code, tables are referenced using #__, which Joomla automatically replaces with the actual table prefix configured in configuration.php.
While a default Joomla site has dozens of tables, these are the main ones you will encounter most often:
- #__content - your articles.
- #__categories - the categories used by articles, contacts, and other content.
- #__users - the user accounts that can log in.
- #__usergroups and #__user_usergroup_map - the user groups and which users belong to them.
- #__menu and #__menu_types - your menu items and the menus they belong to.
- #__modules and #__modules_menu - your modules and the menu pages they appear on.
- #__extensions - every installed component, module, plugin, template, and language.
- #__fields - custom fields added to articles, users, and contacts.
- #__tags - the tags used to label and group content.
- #__template_styles - the configured styles for your templates.
- #__assets - the access control (ACL) permissions tree.
- #__session - active visitor and user sessions.
- #__languages - the languages installed on your site.
You normally never edit these tables by hand. Joomla and its extensions read from and write to them automatically through the administrator interface. Understanding what each table holds is mainly useful for backups, troubleshooting, and development. Some extensions create their own tables, so the total number of database tables varies from one Joomla installation to another.
Direct database edits should only be made when necessary and always after creating a full backup. Incorrect changes can break your website or cause data loss. Whenever possible, use the Joomla Administrator interface or trusted extensions instead of manually editing tables with phpMyAdmin or other database tools.
A Joomla database often grows over time as your website accumulates content, users, logs, sessions, custom fields, extension data, and other information. Third-party extensions can also create their own tables, which may significantly increase the database size. A large database is not necessarily a problem, but removing unused extensions, cleaning expired sessions, and deleting obsolete data can help reduce storage usage and maintain good performance.
To keep your Joomla website fast and reliable:
- regularly remove unused extensions
- clean expired sessions
- optimize database tables using phpMyAdmin or your hosting control panel when appropriate
- repair corrupted tables if necessary
- clear old log data where appropriate
- keep Joomla and its extensions up to date.
Routine Joomla database maintenance improves performance, reduces storage usage, and minimizes the risk of errors.
If the Joomla Database page reports schema differences, you can repair the database by going to Extensions → Manage → Database in the Joomla Administrator. Joomla compares the database structure with the installed version and repairs missing or outdated tables when possible. If the repair does not resolve the issue, restoring a recent backup is often the safest solution.
You can back up a Joomla database using Akeeba Backup, phpMyAdmin, your hosting control panel, or mysqldump. Whenever possible, use Akeeba Backup because it creates a complete backup of both your website files and database. Restoring the database involves importing the SQL backup and ensuring the database credentials in configuration.php match the restored database. Always test your backups before relying on them for disaster recovery.
Yes. You can change the database that Joomla uses after installation, but it requires careful planning. The process involves exporting the existing database, importing it into the new database server, updating the database connection settings in Joomla's configuration.php file, and testing that everything works correctly.
If you are moving to a new hosting provider, this database migration is typically part of the website transfer. Always create a full backup before making any changes.
MySQL and MariaDB are both relational database management systems (RDBMS) that work seamlessly with Joomla. MariaDB is a community-developed fork of MySQL that was created in 2009 after Oracle acquired MySQL.
For most Joomla websites, they are interchangeable. MariaDB is developed by the open source community and is the default database on many Linux servers, while MySQL is developed by Oracle and is available in both Community and commercial editions. Although the two have diverged internally in recent years, Joomla works equally well with both.
Joomla 6 requires MySQL 8.0.13 or higher (recommended: MySQL 8.4), or MariaDB 10.4 or higher (recommended: MariaDB 12.0), see: Joomla! Programmers Documentation: Requirements for Joomla! 6.x
For almost every Joomla website, either database performs equally well. The quality of your hosting, server configuration, caching, and overall website optimization have a much greater impact on performance than whether you choose MySQL or MariaDB.
For most users, the choice simply depends on what their hosting provider offers.
For a new Joomla website, both MySQL and MariaDB are excellent choices. Joomla fully supports both database systems, and most users will notice little or no difference in everyday use.
In practice, your hosting provider usually decides for you. Many shared hosting plans and most Linux distributions now ship MariaDB by default, so that is what a lot of new Joomla sites run on without the owner ever choosing it. The simplest approach is to use whichever database your host offers as standard.
If you do get to choose:
- Choose MariaDB if you want a fully open source database that is highly compatible with MySQL and often delivers excellent performance with lower resource usage. It is the default on most modern hosts.
- Choose MySQL if you prefer the original database system or your hosting provider specifically recommends it.
For most Joomla websites, your choice of hosting, server configuration, caching, and website optimization will have a much greater impact on performance than whether you use MySQL or MariaDB.
In short:
- MariaDB: An excellent choice and the default on many hosting platforms.
- MySQL: Equally reliable and a great choice for maximum compatibility.
- Either option: Fully supported by Joomla and suitable for websites of any size.


