How To Install MySQL on Fedora 44

Install MySQL on Fedora 44

Installing a database server can feel intimidating when you are new to Linux. You might worry about breaking your system or setting weak security. This guide solves those problems by walking you through how to install MySQL on Fedora 44 with clear commands and security best practices.

After 10 years managing Linux servers across Fedora, CentOS, and RHEL environments, I have installed MySQL hundreds of times. Fedora 44 ships with MySQL 8.4 LTS in its default repositories, which means you avoid outdated third-party repo tutorials that still dominate Google search results. You will install MySQL 8.4, set a root password, create an application database and user, configure the firewall, tune for production workloads, and implement backups in under 30 minutes.

This tutorial covers MySQL on Fedora 44 setup from scratch with production-ready security. You will learn not just the commands but also why each step matters for security and performance. Let us configure MySQL on Fedora 44 properly so your database server is secure and ready for real workloads.

Table of Contents

Prerequisites: What You Need Before Installing MySQL on Fedora 44

Before running any commands, verify these requirements to avoid installation failures later.

System Requirements

  • Operating System: Fedora 44 (latest release, confirmed via cat /etc/fedora-release)
  • RAM: Minimum 1 GB for testing, 2 GB or more for real workloads
  • Disk Space: At least 500 MB free for MySQL binaries and initial data files
  • User Permissions: sudo access required (MySQL creates system user during installation)
  • SELinux: Must be in enforcing mode (default on Fedora; do not disable)

Why These Prerequisites Matter

sudo access is mandatory. MySQL creates the mysql system user with GID 27 and UID 27 during installation. Without root privileges, the package manager cannot create this user and installation fails.

2 GB RAM is recommended for production. MySQL 8.4’s InnoDB buffer pool defaults are conservative, but real workloads need memory for the buffer pool. On dedicated MySQL hosts, allocate 50–70 percent of RAM to the buffer pool.

Keep SELinux enforcing. Fedora’s mysql-server package includes mysql-selinux as a dependency, so security policies load automatically. Disabling SELinux removes protection against privilege escalation attacks.

Confirm you are on Fedora 44. Run this command to verify:

cat /etc/fedora-release

Expected output:

Fedora release 44 (Forty Four)

Fedora 44 ships with kernel 6.19, GNOME 50, and Ansible 13. None of these interfere with MySQL, but verifying your version prevents confusion with older Fedora releases.

Step 1: Check the MySQL Package Version Before Installing

What This Command Does

Run this command to see which MySQL version Fedora’s repository provides:

dnf info mysql-server

Why This Step Matters

Checking the package version before installation prevents surprises. You confirm Fedora delivers MySQL 8.4 LTS (not an older 8.0 version) and verify the source RPM matches upstream Oracle builds.

Expected Output

Available packages
Name         : mysql-server
Epoch        : 0
Version      : 8.4.8
Release      : 2.fc44
Architecture : x86_64
Source RPM   : mysql8.4-8.4.8-2.fc44.src.rpm
Repository   : fedora
Summary      : The official MySQL server

What to Verify

Look for Version 8.4.8 with Release 2.fc44. The fc44 tag confirms this is Fedora 44 packaging, not an older version.

If you see a different version (like 8.0.x), your system might be on Fedora 43 or 42. Fedora 44 specifically ships MySQL 8.4.8 LTS.

Step 2: Set Reusable Shell Variables for Passwords and Database Names

What These Commands Do

Define your passwords and database names once before running installation commands:

export MYSQL_ROOT_PW="Strong@Pass2026!"
export APP_DB="appdb"
export APP_USER="appuser"
export APP_USER_PW="AppPass2026!"
export REMOTE_CIDR="10.0.1.0/24"

Verify the variables are set correctly:

echo "Root PW: set (${#MYSQL_ROOT_PW} chars)"
echo "App DB: ${APP_DB}"
echo "App user: ${APP_USER}"

Why This Step Is Critical

Defining passwords and database names once prevents typos in later destructive commands. You will use these variables in multiple SQL commands, and typing them manually each time increases the risk of mistakes.

Password requirements: MySQL’s validate_password plugin requires:

  • At least one uppercase letter
  • At least one lowercase letter
  • At least one digit
  • At least one special character
  • Minimum 8 characters length

The example passwords above satisfy this policy: Strong@Pass2026! has uppercase (S, P), lowercase (trong, ass), digit (2026), special character (@, !), and 15 characters total.

Security note: Never store cleartext passwords in databases. Use SHA2() hashing instead. These shell variables expire when your terminal session ends, which is safer than writing passwords to files.

Step 3: Install MySQL Server from Fedora’s Default Repository

What This Command Does

Install MySQL with a single command:

sudo dnf install -y mysql-server

Why This Method Is Recommended

This single command installs the server, CLI client, shared libraries, and SELinux policy. DNF pulls approximately 22 MiB and creates the mysql system user automatically. You avoid the complexity of Oracle’s community repository, which requires manual RPM installation and generates temporary passwords in log files.

Fedora now includes MySQL 8.4 LTS in default repositories, eliminating the need for third-party repos in most cases.

What Gets Installed

The package manager installs these components:

  • mysql-server (main server package)
  • mysql (CLI client for running queries)
  • mysql-common (shared configuration files)
  • mysql-selinux (SELinux security policies)
  • mariadb-connector-c-config (compatibility layer)
  • mecab (Japanese text processing support)
  • protobuf-lite (serialization library for X Protocol)

Installation Output

Loading mirror speeds from cached hostfile
 * fedora: fedora-mirror-1.example.com
 * updates: updates-mirror.example.com

Dependencies resolved.
================================================================================
 Package               Arch       Version            Repository           Size
================================================================================
Installing:
 mysql-server          x86_64     8.4.8-2.fc44       fedora            12.5 M

Installing dependencies:
 mysql                 x86_64     8.4.8-2.fc44       fedora             3.2 M
 mysql-common          x86_64     8.4.8-2.fc44       fedora             1.1 M
 mysql-selinux         x86_64     8.4.8-2.fc44       fedora             145 k

Transaction Summary
Install  4 Packages

Total download size: 17.0 M
Installed size: 89.5 M
Is this ok [y/N]: y
...
Installed:
  mysql-server-8.4.8-2.fc44.x86_64
  mysql-8.4.8-2.fc44.x86_64
  mysql-common-8.4.8-2.fc44.x86_64
  mysql-selinux-8.4.8-2.fc44.x86_64

Post-Installation Verification

DNF creates /var/lib/mysql data directory owned by mysql:mysql:

ls -ld /var/lib/mysql

Expected output:

drwxr-x---. 2 mysql mysql 184 Jun 18 14:25 /var/lib/mysql

The ownership shows mysql:mysql which confirms the system user was created correctly.

Step 4: Start and Enable the MySQL Service

What This Command Does

Start MySQL immediately and enable it to survive system reboots:

sudo systemctl enable --now mysqld

Why Use `enable –now` Together

The enable flag creates systemd symlinks so MySQL starts automatically on boot. The --now flag starts the service immediately. Combining both flags saves you from running two separate commands.

If you omit --now, MySQL does not start until you reboot. If you omit enable, MySQL starts now but stops after reboot, breaking your application.

Verify the Service Is Running

Check MySQL status:

sudo systemctl status mysqld --no-pager

Expected Output

● mysqld.service - MySQL 8.4 database server
 Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; preset: disabled)
 Active: active (running) since Thu 2026-06-18 14:26:15 WIB
   Docs: man:mysqld(8)
         http://dev.mysql.com/doc/refman/8.4/en/
 Main PID: 15842 (mysqld)
 Status: "Server is operational"
    Tasks: 4 (limit: 7894)
   Memory: 462.6M
      CPU: 2.340s
 CGroup: /system.slice/mysqld.service
 └─15842 /usr/sbin/mysqld

Why Check Status

This confirms the mysql-prepare-db-dir script initialized /var/lib/mysql on first boot and that SELinux policies loaded correctly. The status “Server is operational” means MySQL is ready to accept connections.

If you see failed or activating, check the error log:

sudo journalctl -u mysqld -n 50 --no-pager

Step 5: Verify Server and Client Versions Match

What This Command Does

Check the MySQL client version:

mysql --version

Expected Output

mysql  Ver 8.4.8 for Linux on x86_64 (Source distribution)

Why This Matters

Version mismatches between client and server cause protocol errors. Fedora’s source build matches upstream Oracle 8.4.8, confirming clean packaging. If versions differ, you might have installed client and server from different repositories.

What to verify: The version number (8.4.8) and platform (Linux on x86_64) should match what you saw in Step 1.

Step 6: Set the Root Password (Critical Security Step)

Why Fedora’s Approach Differs from Oracle’s

Fedora’s behavior: On first start, root@localhost uses the auth_socket plugin. Any user with sudo privileges can log in without a password. Fedora does not generate a temporary password in log files.

Oracle’s behavior (alternative repo): Generates a temporary password in /var/log/mysqld.log that you must extract from the log. This is more insecure and requires more steps.

Why Fedora’s approach is better: It prevents accidental exposure of temporary passwords in log files, but requires manual password setting immediately after installation.

Log Into MySQL Without a Password

Since auth_socket is active, use sudo:

sudo mysql

You drop straight into the MySQL prompt:

mysql>

Execute the Password Setup Commands

Run these SQL commands inside the MySQL prompt:

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Strong@Pass2026!';
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';
FLUSH PRIVILEGES;
EXIT;

Why Each Command Is Necessary

ALTER USER 'root'@'localhost' IDENTIFIED BY ...: Swaps the auth_socket plugin to caching_sha2_password, which is modern and secure. Without this step, anyone with sudo can access MySQL as root.

DELETE FROM mysql.user WHERE User='': Removes anonymous users. Anonymous accounts are a security risk because attackers can connect without authentication.

DROP DATABASE IF EXISTS test: Removes the default test database. This database is an attack vector because it exists on every fresh install and often has weak permissions.

DELETE FROM mysql.db WHERE Db='test' ...: Cleans up any remaining test database permissions.

FLUSH PRIVILEGES: Reloads grant tables immediately so changes apply without restarting MySQL.

Verify the Password Works

Test login with the new password:

mysql -uroot -p"${MYSQL_ROOT_PW}" -e "SELECT user, host, plugin FROM mysql.user;"

Expected Output

+------+-----------+-----------------------+
| user | host      | plugin                |
+------+-----------+-----------------------+
| root | localhost | caching_sha2_password |
+------+-----------+-----------------------+

All accounts should show caching_sha2_password instead of auth_socket. This confirms the password is active.

Step 7: Create an Application Database and User

Why You Should Never Use Root for Applications

Security principle: Never run applications as root@localhost. If your application is compromised, the attacker gets full database access to all tables and databases.

MySQL best practice: Create users scoped to specific databases with limited privileges. Use GRANT and REVOKE to control access precisely. This limits the blast radius if credentials are stolen.

Execute Database and User Creation

Run this command to create the database and user in one step:

mysql -uroot -p"${MYSQL_ROOT_PW}" <

Why utf8mb4 Character Set

utf8mb4 supports all Unicode characters, including emoji, Asian languages, and special symbols. The older utf8 in MySQL only supports 3-byte characters and misses many modern characters. utf8mb4_unicode_ci provides case-insensitive sorting with proper Unicode rules.

Why Scoped Privileges Are Important

GRANT ALL PRIVILEGES ON appdb.* limits the user to only the appdb database. The user cannot access other databases like mysql (system tables) or information_schema. This is critical for security.

Verify the Database and User Work

Test the new user connection:

mysql -u"${APP_USER}" -p"${APP_USER_PW}" -e "USE ${APP_DB}; SELECT DATABASE(), CURRENT_USER();"

Expected Output

+------------+----------------+
| DATABASE() | CURRENT_USER() |
+------------+----------------+
| appdb      | appuser@localhost |
+------------+----------------+

This confirms the user can connect and is scoped to appdb.

Step 8: Configure the Firewall for Remote Access

Check What MySQL Is Listening On

Verify which ports MySQL uses:

sudo ss -tlnp | grep -E '3306|33060'

Expected Output

LISTEN 0 151 *:3306 *:* users:(("mysqld",pid=15842,fd=22))
LISTEN 0  70 *:33060 *:* users:(("mysqld",pid=15842,fd=19))

Why Check Ports

Port 3306 is the MySQL classic protocol for SQL queries. Port 33060 is the X Protocol for JSON/document store operations. Both bind to all interfaces by default, which means MySQL accepts connections from any network.

On a production server, you should restrict access to your application servers only.

Add Firewall Rule for Your Subnet

Open MySQL port permanently:

sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload

Why Use `–permanent` and `–reload`

The --permanent flag writes the rule to the configuration file so it survives reboots. The --reload flag activates the rule immediately without restarting firewalld.

If you omit --permanent, the rule disappears after reboot and your application stops working.

Better Security: Subnet-Specific Rule

Restrict MySQL access to your application server subnet only:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" port port="3306" protocol="tcp" accept"'
sudo firewall-cmd --reload

Why Subnet Restriction Is Critical

Limiting MySQL access to 10.0.1.0/24 (your application servers) prevents unauthorized machines from connecting. Never expose port 3306 to 0.0.0.0/0 (the public internet). Database ports should never be public.

Verify the Firewall Rule Is Active

Check which ports are open:

sudo firewall-cmd --list-ports

Expected Output

3306/tcp

This confirms MySQL port is accessible.

Step 9: Tune MySQL for Production Workloads

Why Default Configuration Is Only Good for Development

Fedora’s default configuration uses conservative InnoDB settings designed for testing. On a dedicated MySQL host with 8 GB RAM, you should allocate 4–5 GB to the buffer pool. Default settings are much lower and cause excessive disk I/O.

Performance impact: Wrong buffer pool size slows queries 10–100 times because MySQL reads from disk instead of memory.

Edit the Configuration File

Open Fedora’s MySQL drop-in config file:

sudo vi /etc/my.cnf.d/community-mysql-server.cnf

Why This File

Fedora uses drop-in configuration files in /etc/my.cnf.d/. This is the main server config file, not /etc/my.cnf (which is the primary file but often empty on Fedora).

Add Production Settings Under `[mysqld]`

Add these lines under the [mysqld] section:

[mysqld]
# Memory configuration
innodb_buffer_pool_size = 4G
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT

# Connection limits
max_connections = 200
wait_timeout = 600

# Binary logging for replication and point-in-time recovery
server-id = 1
log_bin = mysql-bin
binlog_format = ROW
expire_logs_days = 7

# Character set for Unicode support
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

Why Each Setting Matters

innodb_buffer_pool_size = 4G: Allocates 50 percent of 8 GB RAM to the buffer pool. This holds data and indexes in memory, which is the single biggest performance factor for MySQL.

innodb_log_file_size = 512M: Larger transaction logs reduce I/O frequency during writes. Default is usually 128M, which is too small for production.

innodb_flush_log_at_trx_commit = 1: Ensures maximum durability. Every transaction flushes logs to disk immediately, making MySQL crash-safe.

innodb_flush_method = O_DIRECT: Avoids double-buffering with the OS cache. This reduces memory usage and improves write performance.

max_connections = 200: Prevents connection exhaustion attacks. Default is 151, which is too low for web applications.

wait_timeout = 600: Closes idle connections after 10 minutes. Default is 8 hours, which wastes memory.

log_bin and binlog_format = ROW: Enables binary logging for replication and point-in-time recovery. ROW format logs individual row changes, which is more precise than statement-based logging.

expire_logs_days = 7: Automatically deletes binary logs older than 7 days. This prevents the logs directory from filling disk space.

character-set-server = utf8mb4: Sets the default character set to support all Unicode.

Apply Configuration Changes

Restart MySQL to load the new settings:

sudo systemctl restart mysqld

Verify Settings Are Active

Check key variables:

mysql -uroot -p"${MYSQL_ROOT_PW}" -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_buffer_pool_size','max_connections','character_set_server','log_bin');"

Expected Output

+----------------------+----------+
| Variable_name        | Value    |
+----------------------+----------+
| innodb_buffer_pool_size | 4294967296 |
| max_connections        | 200      |
| character_set_server   | utf8mb4  |
| log_bin                | ON       |
+----------------------+----------+

Note: 4294967296 bytes equals 4 GB.

Step 10: Back Up Your Database with mysqldump

Why Backups Are Non-Negotiable

MySQL security guidelines require adequate backups of database files, configuration, and log files. Without backups, hardware failure, human error, or ransomware can destroy your data permanently.

Recovery time objective: Daily backups with 7-day retention (configured via expire_logs_days in Step 9) enable point-in-time recovery.

Execute Backup Command

Create a compressed backup of your application database:

mysqldump -uroot -p"${MYSQL_ROOT_PW}" \
 --single-transaction --routines --triggers --events \
 "${APP_DB}" | gzip > "${APP_DB}-$(date +%F).sql.gz"

Why Each Flag Is Important

--single-transaction: Creates a consistent snapshot for InnoDB tables without locking. This allows your application to continue writing while the backup runs.

--routines: Includes stored functions and procedures in the backup. Without this, you lose application logic.

--triggers: Includes table triggers. Without this, automated actions defined in your database are lost.

--events: Includes scheduled events. Without this, cron-like database jobs are lost.

gzip: Compresses the backup file. Compressed backups are 5–10 times smaller than uncompressed SQL dumps.

Expected Backup Filename

appdb-2026-06-18.sql.gz

The date format ensures unique filenames for daily backups.

Verify Backup File Exists

Check the backup was created:

ls -lh appdb-*.sql.gz

Expected Output

-rw-r--r--. 1 root root 245K Jun 18 14:35 appdb-2026-06-18.sql.gz

A 245 KB compressed backup indicates the database has data.

Test Backup by Restoring

Restore the backup to verify it works:

gunzip < "appdb-2026-06-18.sql.gz" | mysql -uroot -p"${MYSQL_ROOT_PW}" "${APP_DB}"

Why Test Restores Regularly

Run restore tests on a test server monthly to verify backup integrity. A backup you cannot restore is useless.

For Large Databases Over 100 GB

Use parallel backup tools instead:

  • mysqlpump (parallel mysqldump)
  • mysqlsh dump-instance (MySQL Shell)

These handle large databases more efficiently.

Troubleshooting: Common MySQL Installation Errors on Fedora 44

Error 1: Access denied for user ‘root’@’localhost’ (using password: NO)

Cause: You ran mysql without sudo before setting a real root password. Fedora’s fresh install uses auth_socket, so only sudo mysql works initially.

Solution:

sudo mysql

Then follow Step 6 to set the password and switch to caching_sha2_password.

Error 2: Your password does not satisfy the current policy requirements

Cause: The validate_password plugin rejected your password. Default policy requires uppercase, lowercase, digit, special character, and minimum 8 characters.

Solution (use stronger password):

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Strong@Pass2026!';

Solution (relax policy – NOT for production):

SET GLOBAL validate_password.policy = LOW;

Warning: LOW drops the policy to length-only only. Never lower this on internet-facing servers.

Error 3: mysqld fails to start with “Failed to initialize ACL/file permissions”

Cause: The /var/lib/mysql directory ownership is wrong (should be mysql:mysql) or the SELinux label is broken after manual file movement.

Solution:

sudo chown -R mysql:mysql /var/lib/mysql
sudo restorecon -Rv /var/lib/mysql
sudo systemctl restart mysqld

Why `restorecon`: Resets the SELinux context to the policy default. Without this, mysqld cannot read data files in enforcing mode.

Error 4: Cannot connect to remote MySQL from another host

Check these in order:

1. User grant covers source IP:

mysql -uroot -p"${MYSQL_ROOT_PW}" -e "SELECT user, host FROM mysql.user WHERE user='${APP_USER}';"

Expected: appuser@localhost or appuser@10.0.1.%

2. mysqld bound to correct interface:

sudo ss -tlnp | grep 3306

Expected: *:3306 (all interfaces)

3. firewalld allows 3306/tcp:

sudo firewall-cmd --list-ports

Expected: 3306/tcp

Network test from remote machine:

nc -vz HOST 3306

If this fails, it is a network or firewall issue. If it succeeds but MySQL authentication fails, it is a user grant issue.

Error 5: Command not found: mysql

Cause: The MySQL client is not in your PATH, or you installed only the server package.

Solution:

sudo dnf install -y mysql

This installs the CLI client.

Common MySQL Administration Commands for Day-to-Day Work

Quick Command Reference

Command What It Does
sudo systemctl status mysqld Check if mysqld is running
sudo systemctl restart mysqld Apply configuration changes
mysql -uroot -p Interactive root login
mysql -uUSER -p DB < file.sql Import SQL dump non-interactively
mysqldump -uroot -p --all-databases Dump everything to stdout
SHOW DATABASES; List all databases
SHOW PROCESSLIST; See active connections and queries
SHOW ENGINE INNODB STATUS\G InnoDB diagnostic dump
SHOW VARIABLES LIKE 'innodb%'; Inspect InnoDB settings
SHOW GRANTS FOR 'user'@'host'; Print effective permissions
FLUSH PRIVILEGES; Reload grant tables after manual edits

Why memorize these: These are the commands you will use daily for monitoring, debugging, and maintenance tasks.

Key File Locations: Where Everything Lives on Fedora

Essential Paths to Know

File or Directory Purpose
/etc/my.cnf Primary configuration file
/etc/my.cnf.d/ Drop-in directory (Fedora-specific)
/var/lib/mysql/ Data directory containing tables and indexes
/var/log/mysqld.log Error log (Oracle repo temporary password stored here)

Why know these locations: When troubleshooting, you need to check logs, edit configuration files, or verify data directory ownership.

SELinux Notes: Fedora’s Security Model Will Not Block MySQL

Why You Should Leave SELinux Enforcing

Fedora’s mysql-server package ships with mysql-selinux as a dependency, so security policies load automatically. The daemon runs cleanly in enforcing mode with no need to disable SELinux.

Disabling SELinux is bad practice because it protects against privilege escalation and file system attacks.

If You Change the Data Directory

If you move MySQL data to a custom location (like /data/mysql), update SELinux context:

sudo semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"
sudo restorecon -Rv /data/mysql

Why this is necessary: Custom data directories need SELinux context updated. Without this change, mysqld cannot write files in enforcing mode.

r00t is a Linux Systems Administrator and open-source advocate with over ten years of hands-on experience in server infrastructure, system hardening, and performance tuning. Having worked across distributions such as Debian, Arch, RHEL, and Ubuntu, he brings real-world depth to every article published on this blog. r00t writes to bridge the gap between complex sysadmin concepts and practical, everyday application — whether you are configuring your first server or optimizing a production environment. Based in New York, US, he is a firm believer that knowledge, like open-source software, is best when shared freely.

Related Posts