Changing the TCP port for MySQL or MariaDB helps separate multiple database instances on one host, moves the listener off the default scan target at 3306, and aligns the service with network policies or load balancer expectations that reserve a different port number.
The server opens its classic SQL listener from the startup-only port setting under [mysqld], so the safest workflow is to confirm the active option-file chain first, place the override in a loaded server include directory, and then restart the service. Current package installs often split server defaults across several files under /etc/mysql/ or /etc/my.cnf.d/, which is why my_print_defaults mysqld is useful before the restart.
Every TCP client, firewall rule, health check, and connection string that still assumes 3306 must be updated after the change. Local Unix-socket administration can still work even when the TCP port moves, and remote clients can still fail if bind-address, account host matching, or SELinux policy does not allow the new listener. Avoid privileged ports below 1024 unless the service is deliberately configured with the extra capability that bind requires.
$ server_bin=$(command -v mariadbd || command -v mysqld) $ "$server_bin" --verbose --help 2>/dev/null | sed -n '/Default options are read from the following files in the given order:/,+3p' Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf ##### snipped #####
The local host is authoritative here. Current MariaDB reports the option groups it reads in the same output, while current MySQL package installs can also report extra distro-specific paths such as /usr/etc/my.cnf/.
$ sudo grep -nE '^(\\!include|\\!includedir)' /etc/my.cnf /etc/mysql/my.cnf /etc/mysql/mariadb.cnf 2>/dev/null /etc/mysql/my.cnf:28:!includedir /etc/mysql/conf.d/ /etc/mysql/my.cnf:29:!includedir /etc/mysql/mariadb.conf.d/
On MariaDB packages for Debian and Ubuntu, the last loaded server directory is commonly /etc/mysql/mariadb.conf.d/. On MySQL packages, use the last server include directory actually referenced by the base file, commonly /etc/mysql/conf.d/ or /etc/mysql/mysql.conf.d/.
The classic SQL listener defaults to 3306. On MySQL with X Plugin enabled, mysqlx_port remains separate and normally stays on 33060 unless it is changed explicitly.
$ sudoedit /etc/mysql/mariadb.conf.d/z-custom-port.cnf
[mysqld] is the safest cross-compatible option group for this change. MariaDB also reads [server], [mariadb], and [mariadbd], but [mysqld] keeps one file working across both server families.
[mysqld] port = 3307
Any TCP client, application pool, replication channel, proxy, or health check that still targets 3306 will fail until its connection settings are updated.
$ my_print_defaults mysqld | grep -- '^--port=' --port=3307
If the expected line does not appear, the file is in the wrong path, under the wrong option group, or overridden later in the include chain.
$ systemctl list-unit-files --type=service | grep --extended-regexp '^(mysql|mariadb|mysqld)\\.service' mariadb.service enabled enabled
Depending on packaging, the service may be called mysql, mariadb, or mysqld.
$ sudo systemctl restart mariadb
Restarting drops active connections, so schedule the change when applications can tolerate a short interruption.
Replace mariadb with the discovered unit name on the host.
$ systemctl is-active mariadb active
If the service does not return active, inspect the recent journal before editing again.
$ sudo journalctl --unit=mariadb.service --no-pager --lines=50 ##### snipped #####
$ client_bin=$(command -v mariadb || command -v mysql) $ sudo "$client_bin" --table --execute "SHOW VARIABLES LIKE 'port';" +---------------+-------+ | Variable_name | Value | +---------------+-------+ | port | 3307 | +---------------+-------+
Socket-auth installs often allow sudo mariadb or sudo mysql without a password prompt. If the local admin account uses password authentication instead, drop sudo and add --user plus --password.
$ sudo ss --listening --numeric --tcp | grep ':3307 ' LISTEN 0 80 127.0.0.1:3307 0.0.0.0:*
If no :3307 listener appears and a broader ss check still shows :3306, another later option file is overriding port or the service did not restart with the edited file.
$ sudo ufw allow 3307/tcp Rule added Rule added (v6)
On RHEL-family systems, use firewall-cmd –permanent –add-port=3307/tcp followed by firewall-cmd –reload instead.
On SELinux systems, label the new port for mysqld before expecting remote TCP connections to work, for example with semanage port -a -t mysqld_port_t -p tcp 3307 when the port is not already assigned.
$ sudo ufw delete allow 3306/tcp Rule deleted Rule deleted (v6)
Keep the old rule until application pools, replica configs, backup jobs, and monitoring checks have all been updated to the new port.
$ client_bin=$(command -v mariadb || command -v mysql) $ "$client_bin" --protocol=TCP --host=192.0.2.40 --port=3307 --user=appuser --password --table --execute "SELECT @@port AS port, CURRENT_USER() AS current_login;" Enter password: +------+-------------------+ | port | current_login | +------+-------------------+ | 3307 | appuser@192.0.2.% | +------+-------------------+
If the local socket login works but the TCP test fails, recheck bind-address, host firewall rules, account host matching such as 'appuser'@'192.0.2.%', and any upstream security group or ACL still tied to 3306.