Can't connect to MySQL without SSL
Hi!
I try to migrate from dovecot 2.3 to dovecot CE 2.4, but within a docker container. But I always get the following error from Dovecot CE:
Error: auth: mysql(host.docker.internal): Connect failed to database (foobar): TLS/SSL error: self-signed certificate in certificate chain - waiting for 1 seconds before retry
This is how I configured the mysql connection:
mysql host.docker.internal { host = host.docker.internal port = 3306 user = ... password = ... dbname = foobar ssl = no }
So MySQL runs on the host machine directly, not in a container - therefore I'm using "host.docker.internal" as an host. But I don't need SQL encryption, since both MySQL and Dovecot run on the same machine. So why the heck does it look like, Dovecot is trying to connect using SSL?
Best regards, Billie
Hello,
did mysql require secure transport (require_secure_transport=ON)? you can try
mysql { mysql_host = db.example.com mysql_dbname = mail mysql_user = dovecot mysql_password = secret
mysql_ssl = yes ssl_client_require_valid_cert = no }
Am 04.08.26 um 22:25 schrieb dovecot--- via dovecot:
Hi!
I try to migrate from dovecot 2.3 to dovecot CE 2.4, but within a docker container. But I always get the following error from Dovecot CE:
Error: auth: mysql(host.docker.internal): Connect failed to database (foobar): TLS/SSL error: self-signed certificate in certificate chain - waiting for 1 seconds before retry
This is how I configured the mysql connection:
mysql host.docker.internal { host = host.docker.internal port = 3306 user = ... password = ... dbname = foobar ssl = no }
So MySQL runs on the host machine directly, not in a container - therefore I'm using "host.docker.internal" as an host. But I don't need SQL encryption, since both MySQL and Dovecot run on the same machine. So why the heck does it look like, Dovecot is trying to connect using SSL?
Best regards, Billie
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
On 4. Aug 2026, at 23.25, dovecot--- via dovecot <dovecot@dovecot.org> wrote:
I try to migrate from dovecot 2.3 to dovecot CE 2.4, but within a docker container. But I always get the following error from Dovecot CE:
Error: auth: mysql(host.docker.internal): Connect failed to database (foobar): TLS/SSL error: self-signed certificate in certificate chain - waiting for 1 seconds before retry
This is how I configured the mysql connection:
mysql host.docker.internal { host = host.docker.internal port = 3306 user = ... password = ... dbname = foobar ssl = no }
So MySQL runs on the host machine directly, not in a container - therefore I'm using "host.docker.internal" as an host. But I don't need SQL encryption, since both MySQL and Dovecot run on the same machine. So why the heck does it look like, Dovecot is trying to connect using SSL?
Looks like mysql_ssl=no doesn't actually disable it, it just leaves it the default, which is "preferred". For now you can use:
mysql host.docker.internal { ... option_file = /etc/dovecot/mysql-client.cnf } /etc/dovecot/mysql-client.cnf: [client] ssl-mode=DISABLED
I'll see about changing this in some way to be better.
@basti require_secure_transport is OFF, I had checked that.
Hi Timo!
Creating the mysql-client.cnf didn't change the behavior, it tries to connect even with this minimal configuration:
/etc/dovecot/dovecot.conf: sql_driver = mysql
mysql host.docker.internal { option_file = /etc/dovecot/mysql-client.cnf }
/etc/dovecot/mysql-client.cnf: [client] ssl-mode=DISABLED
Still gets me an error: TLS/SSL error: self-signed certificate in certificate chain
In the meantime I will try to make it work using SSL. But the last time I tried it somehow conflicted with the "ssl_server_cert_file" and "ssl_server_key_file" which point to the certbot/letsencrypt certificates while MySQL generates self-signed certificates.
Thanks for your help so far!
Here’s a basic configuration for a Dovecot 2.4.0 server. This should help you with the MySQL connection. If you are using an older version of Dovecot than 2.4.0, I would recommend upgrading. Also note, this is a single file configuration!
=============================================================================
Dovecot 2.4 CE configuration
Single-file configuration — do not use /etc/dovecot/conf.d/
=============================================================================
Required in 2.4: declares config syntax version and storage format
version.
These MUST be the first settings in the file.
dovecot_config_version = 2.4.0 dovecot_storage_version = 2.4.0
——————————————————————————————————————
Global
——————————————————————————————————————
protocols = imap lmtp listen = * base_dir = /var/run/dovecot instance_name = <HOSTNAME> hostname = <HOSTNAME> login_greeting = Welcome postmaster_address = <POSTMASTER> mail_server_admin = mailto:<POSTMASTER>
default_internal_user = vmail default_internal_group = vmail
——————————————————————————————————————
Logging
——————————————————————————————————————
log_path = /var/log/dovecot/general.log info_log_path = /var/log/dovecot/info.log debug_log_path = /var/log/dovecot/debug.log
log_debug = category=auth OR category=mail OR category=sieve auth_verbose_passwords = no
——————————————————————————————————————
SSL / TLS
——————————————————————————————————————
ssl = required ssl_server_cert_file = /etc/letsencrypt/live/<HOSTNAME>/fullchain.pem ssl_server_key_file = /etc/letsencrypt/live/<HOSTNAME>/privkey.pem ssl_server_dh_file = /usr/share/dovecot/dh.pem ssl_client_ca_dir = /etc/ssl/certs ssl_min_protocol = TLSv1.2 ssl_server_prefer_ciphers = server
——————————————————————————————————————
Mail storage
——————————————————————————————————————
mail_driver = maildir mail_path = ~/ mail_home = %{user | domain}/%{user | username}
maildir_stat_dirs = yes
mail_max_userip_connections = 250
——————————————————————————————————————
Namespaces
——————————————————————————————————————
namespace inbox { inbox = yes separator = / prefix =
mailbox Archive { auto = subscribe special_use = \Archive } mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Junk { auto = subscribe special_use = \Junk autoexpunge = 90d } mailbox Sent { auto = subscribe special_use = \Sent } mailbox Trash { auto = subscribe special_use = \Trash autoexpunge = 30d } }
——————————————————————————————————————
Auth: mechanisms and behavior
——————————————————————————————————————
auth_mechanisms = plain login auth_username_format = %{user | lower} auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_@
auth_cache_size = 64M auth_cache_ttl = 10mins auth_cache_negative_ttl = 1mins
——————————————————————————————————————
MySQL connection (used by passdb, userdb, and quota_clone dict)
——————————————————————————————————————
mysql mail-db { host = <DB_HOSTNAME> user = <DB_USERNAME> password = <DB_PASSWORD> dbname = <DB_DATABASE> }
sql_driver = mysql
——————————————————————————————————————
passdb: SQL-backed password lookup
——————————————————————————————————————
passdb sql { default_password_scheme = BLF-CRYPT
query = SELECT Mailbox.email AS user, Mailbox.password FROM
mailbox Mailbox WHERE Mailbox.email = '%{user | lower}' AND
Mailbox.isActive = 1 AND Mailbox.domainUuid IN (SELECT
Domain.uuid FROM domain Domain WHERE Domain.isActive = 1)
}
——————————————————————————————————————
userdb: SQL-backed user lookup
——————————————————————————————————————
userdb sql {
query = SELECT Mailbox.maildir AS home, 5000 AS uid, 5000 AS
gid, CASE WHEN Mailbox.quotaSize IS NOT NULL AND
Mailbox.quotaMessages IS NOT NULL THEN CONCAT('*:bytes=',
Mailbox.quotaSize, ':messages=', Mailbox.quotaMessages) ELSE
NULL END AS quota_rule FROM mailbox Mailbox WHERE
Mailbox.email = '%{user | lower}' AND Mailbox.isActive = 1 AND
Mailbox.domainUuid IN (SELECT Domain.uuid FROM domain Domain
WHERE Domain.isActive = 1)
iterate_query = SELECT Mailbox.email AS username FROM mailbox
Mailbox WHERE Mailbox.isActive = 1 AND Mailbox.domainUuid IN
(SELECT Domain.uuid FROM domain Domain WHERE Domain.isActive
= 1) ORDER BY Mailbox.domainName ASC, Mailbox.email ASC
}
——————————————————————————————————————
Plugins (loaded globally)
——————————————————————————————————————
mail_plugins { quota = yes quota_clone = yes }
——————————————————————————————————————
Quota: count driver (authoritative, no enforcement)
——————————————————————————————————————
quota user { driver = count }
——————————————————————————————————————
Quota clone: mirror live usage into MariaDB mailboxQuota table
——————————————————————————————————————
dict_server { dict quotaclone { driver = sql sql_driver = mysql
dict_map priv/quota/storage {
sql_table = mailboxQuota
username_field = email
value_field size {
}
}
dict_map priv/quota/messages {
sql_table = mailboxQuota
username_field = email
value_field messages {
}
}
} }
quota_clone { dict proxy { name = quotaclone } }
——————————————————————————————————————
Service: auth (SMTP AUTH for Postfix, plus auth-userdb socket)
——————————————————————————————————————
service auth { user = vmail group = vmail
unix_listener /var/spool/postfix/private/auth { user = postfix group = postfix mode = 0660 }
unix_listener auth-userdb { user = vmail group = vmail mode = 0660 } }
service auth-worker { user = vmail group = vmail process_limit = 4 }
——————————————————————————————————————
Service: lmtp (mail delivery from Postfix)
——————————————————————————————————————
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { user = postfix group = postfix mode = 0660 } }
——————————————————————————————————————
Service: imap-login (IMAPS on 993; plain IMAP disabled)
——————————————————————————————————————
service imap-login { inet_listener imap { port = 0 }
inet_listener imaps { port = 993 ssl = yes }
restart_request_count = unlimited process_min_avail = 8 }
service imap { vsz_limit = 4G }
——————————————————————————————————————
Service: submission-login (disabled — Postfix handles 587/465)
——————————————————————————————————————
service submission-login { inet_listener submission { port = 0 } }
——————————————————————————————————————
Service: pop3-login (disabled)
——————————————————————————————————————
service pop3-login { inet_listener pop3 { port = 0 } inet_listener pop3s { port = 0 } }
——————————————————————————————————————
Service: quota-status (Postfix recipient-time quota check)
——————————————————————————————————————
service quota-status { executable = /usr/lib/dovecot/quota-status -p postfix unix_listener /var/spool/postfix/private/quota-status { user = postfix } }
Adam L Miller
------ Original Message ------ From "dovecot--- via dovecot" <dovecot@dovecot.org> To dovecot@dovecot.org Date 8/5/2026 2:47:30 PM Subject Re: Can't connect to MySQL without SSL
@basti require_secure_transport is OFF, I had checked that.
Hi Timo!
Creating the mysql-client.cnf didn't change the behavior, it tries to connect even with this minimal configuration:
/etc/dovecot/dovecot.conf: sql_driver = mysql
mysql host.docker.internal { option_file = /etc/dovecot/mysql-client.cnf }
/etc/dovecot/mysql-client.cnf: [client] ssl-mode=DISABLED
Still gets me an error: TLS/SSL error: self-signed certificate in certificate chain
In the meantime I will try to make it work using SSL. But the last time I tried it somehow conflicted with the "ssl_server_cert_file" and "ssl_server_key_file" which point to the certbot/letsencrypt certificates while MySQL generates self-signed certificates.
Thanks for your help so far!
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
Here's a basic configuration for a Dovecot 2.4.0 server. This should help you with the MySQL connection. If you are using an older version of Dovecot than 2.4.0, I would recommend upgrading. Also note, this is a single file configuration!
=============================================================================
Dovecot 2.4 CE configuration
Single-file configuration -- do not use /etc/dovecot/conf.d/
=============================================================================
Required in 2.4: declares config syntax version and storage format
version.
These MUST be the first settings in the file.
dovecot_config_version = 2.4.0 dovecot_storage_version = 2.4.0
Global
protocols = imap lmtp listen = * base_dir = /var/run/dovecot instance_name = <HOSTNAME> hostname = <HOSTNAME> login_greeting = Welcome postmaster_address = <POSTMASTER> mail_server_admin = mailto:<POSTMASTER> default_internal_user = vmail default_internal_group = vmail
Logging
log_path = /var/log/dovecot/general.log info_log_path = /var/log/dovecot/info.log debug_log_path = /var/log/dovecot/debug.log log_debug = category=auth OR category=mail OR category=sieve auth_verbose_passwords = no
SSL / TLS
ssl = required ssl_server_cert_file = /etc/letsencrypt/live/<HOSTNAME>/fullchain.pem ssl_server_key_file = /etc/letsencrypt/live/<HOSTNAME>/privkey.pem ssl_server_dh_file = /usr/share/dovecot/dh.pem ssl_client_ca_dir = /etc/ssl/certs ssl_min_protocol = TLSv1.2 ssl_server_prefer_ciphers = server
Mail storage
mail_driver = maildir mail_path = ~/ mail_home = %{user | domain}/%{user | username} maildir_stat_dirs = yes mail_max_userip_connections = 250
Namespaces
namespace inbox { inbox = yes separator = / prefix = mailbox Archive { auto = subscribe special_use = \Archive } mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Junk { auto = subscribe special_use = \Junk autoexpunge = 90d } mailbox Sent { auto = subscribe special_use = \Sent } mailbox Trash { auto = subscribe special_use = \Trash autoexpunge = 30d } }
Auth: mechanisms and behavior
auth_mechanisms = plain login auth_username_format = %{user | lower} auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_@ auth_cache_size = 64M auth_cache_ttl = 10mins auth_cache_negative_ttl = 1mins
MySQL connection (used by passdb, userdb, and quota_clone dict)
mysql mail-db { host = <DB_HOSTNAME> user = <DB_USERNAME> password = <DB_PASSWORD> dbname = <DB_DATABASE> } sql_driver = mysql
passdb: SQL-backed password lookup
passdb sql {
default_password_scheme = BLF-CRYPT
query = SELECT Mailbox.email AS user, Mailbox.password FROM
mailbox Mailbox WHERE Mailbox.email = '%{user | lower}' AND
Mailbox.isActive = 1 AND Mailbox.domainUuid IN (SELECT
Domain.uuid FROM domain Domain WHERE Domain.isActive = 1)
}
userdb: SQL-backed user lookup
userdb sql {
query = SELECT Mailbox.maildir AS home, 5000 AS uid, 5000 AS
gid, CASE WHEN Mailbox.quotaSize IS NOT NULL AND
Mailbox.quotaMessages IS NOT NULL THEN CONCAT('*:bytes=',
Mailbox.quotaSize, ':messages=', Mailbox.quotaMessages) ELSE NULL
END AS quota_rule FROM mailbox Mailbox WHERE Mailbox.email =
'%{user | lower}' AND Mailbox.isActive = 1 AND Mailbox.domainUuid
IN (SELECT Domain.uuid FROM domain Domain WHERE
Domain.isActive = 1)
iterate_query = SELECT Mailbox.email AS username FROM mailbox
Mailbox WHERE Mailbox.isActive = 1 AND Mailbox.domainUuid IN
(SELECT Domain.uuid FROM domain Domain WHERE Domain.isActive =
- ORDER BY
Mailbox.domainNameASC,Mailbox.emailASC }
Plugins (loaded globally)
mail_plugins { quota = yes quota_clone = yes }
Quota: count driver (authoritative, no enforcement)
quota user { driver = count }
Quota clone: mirror live usage into MariaDB mailboxQuota table
dict_server { dict quotaclone { driver = sql sql_driver = mysql dict_map priv/quota/storage { sql_table = mailboxQuota username_field = email value_field size { } } dict_map priv/quota/messages { sql_table = mailboxQuota username_field = email value_field messages { } } } } quota_clone { dict proxy { name = quotaclone } }
Service: auth (SMTP AUTH for Postfix, plus auth-userdb socket)
service auth { user = vmail group = vmail unix_listener /var/spool/postfix/private/auth { user = postfix group = postfix mode = 0660 } unix_listener auth-userdb { user = vmail group = vmail mode = 0660 } } service auth-worker { user = vmail group = vmail process_limit = 4 }
Service: lmtp (mail delivery from Postfix)
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { user = postfix group = postfix mode = 0660 } }
Service: imap-login (IMAPS on 993; plain IMAP disabled)
service imap-login { inet_listener imap { port = 0 } inet_listener imaps { port = 993 ssl = yes } restart_request_count = unlimited process_min_avail = 8 } service imap { vsz_limit = 4G }
Service: submission-login (disabled -- Postfix handles 587/465)
service submission-login { inet_listener submission { port = 0 } }
Service: pop3-login (disabled)
service pop3-login { inet_listener pop3 { port = 0 } inet_listener pop3s { port = 0 } }
Service: quota-status (Postfix recipient-time quota check)
service quota-status { executable = /usr/lib/dovecot/quota-status -p postfix unix_listener /var/spool/postfix/private/quota-status { user = postfix } } Adam L Miller ------ Original Message ------ From "dovecot--- via dovecot" <[1]dovecot@dovecot.org> To [2]dovecot@dovecot.org Date 8/5/2026 2:47:30PM Subject Re: Can't connect to MySQL without SSL
@basti require_secure_transport is OFF, I had checked that.
Hi Timo!
Creating the mysql-client.cnf didn't change the behavior, it tries to
connect even with this minimal configuration:
/etc/dovecot/dovecot.conf:
sql_driver = mysql
mysql host.docker.internal {
option_file = /etc/dovecot/mysql-client.cnf
}
/etc/dovecot/mysql-client.cnf:
[client]
ssl-mode=DISABLED
Still gets me an error:
TLS/SSL error: self-signed certificate in certificate chain
In the meantime I will try to make it work using SSL. But the last time
I tried it somehow conflicted with the "ssl_server_cert_file" and
"ssl_server_key_file" which point to the certbot/letsencrypt
certificates while MySQL generates self-signed certificates.
Thanks for your help so far!
_______________________________________________
dovecot mailing list -- [3]dovecot@dovecot.org
To unsubscribe send an email to [4]dovecot-leave@dovecot.org
References
Visible links
- mailto:dovecot@dovecot.org
- mailto:dovecot@dovecot.org
- mailto:dovecot@dovecot.org
- mailto:dovecot-leave@dovecot.org
Sorry to wander in in the middle of this but, Is the mysql server set to only take ssl?
In the database,
SHOW VARIABLES LIKE 'have_ssl';
or test with,
mysql -h <server> -u <user> -p --ssl-mode=DISABLED
Here are my notes for a mariadb ssl self cert but its very close for mysql, (and a different app but again should help)
to turn of,
[mariadb]
#ssl=0
and restart mysql/mariadb
Notes on making a ssl setup.
Mariadb/Mysql SSL/TLS
Thursday, 4 June 2026
12:45 pm
Database TLS
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/pdf/con...
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/html/co...
https://docs.faveohelpdesk.com/docs/installation/providers/enterprise/redhat...
Database files,
ssl directory (set via ansible)
mkdir -p /var/lib/mysql/ssl
Create a Certificate Authority (CA)
cd /var/lib/mysql/ssl
Generate CA private key
openssl genrsa 2048 > mariadb-ca-key.pem
Generate CA certificate
openssl req -new -x509 -nodes -days 3650 \
-key mariadb-ca-key.pem \
-out mariadb-ca-cert.pem
Generate Server Key and Certificate
Create server private key
openssl genrsa 2048 > mariadb-server-key.pem
Create certificate signing request (CSR)
openssl req -new -key mariadb-server-key.pem -out mariadb-server-req.pem
We now have 4 files,
mariadb-ca-cert.pem
mariadb-ca-key.pem
mariadb-server-key.pem
mariadb-server-req.pem
openssl x509 -req -in mariadb-server-req.pem \
-days 3650 \
-CA mariadb-ca-cert.pem \
-CAkey mariadb-ca-key.pem \
-set_serial 01 \
-out mariadb-server-cert.pem
We now have 5 files,
mariadb-ca-cert.pem
mariadb-ca-key.pem
mariadb-server-cert.pem
mariadb-server-key.pem
mariadb server-req.pem
Now do the sym links
ln -s /var/lib/mysql/ssl/mariadb-ca-key.pem /etc/pki/tls/private/mariadb-ca-key.pem ln -s /var/lib/mysql/ssl/mariadb-server-key.pem /etc/pki/tls/private/mariadb-server-key.pem
ln -s /var/lib/mysql/ssl/mariadb-ca-cert.pem /etc/pki/tls/certs/mariadb-ca-cert.pem
ln -s /var/lib/mysql/ssl/mariadb-server-cert.pem /etc/pki/tls/certs/mariadb-server-cert.pem
vi /etc/my.cnf.d/mariadb-server-tls.cnf
[mysqld]
ssl-ca=/path/to/ca.pem
ssl-cert=/path/to/server-cert.pem
ssl-key=/path/to/server-key.pem
[mariadb]
ssl_key = /var/lib/mysql/ssl/mariadb-server-key.pem
ssl_cert = /var/lib/mysql/ssl/mariadb-server-cert.pem
ssl_ca = /var/lib/mysql/ssl/mariadb-ca-key.pem
tls_version = TLSv1.3
#ssl=0
Verify the output hashes match,
openssl x509 -noout -modulus -in /etc/pki/tls/certs/mariadb-server-cert.pem | openssl md5 openssl rsa -noout -modulus -in /etc/pki/tls/private/mariadb-server-key.pem | openssl md5
Set ownership
chown mysql: *
Restart the database,
systemctl restart mysql
Check ssl is working,
SHOW VARIABLES LIKE 'have_ssl';
Check TLS version
mysql -u root -p
SHOW GLOBAL VARIABLES LIKE 'tls_version';
Other checks,
SHOW VARIABLES LIKE 'have_openssl';
SHOW STATUS LIKE 'Ssl_cipher';
Client side
cd /var/lib/mysql/ssl
Client key
openssl genrsa 2048 > redcap-sandpit-client-key.pem
Client CSR
openssl req -new -key redcap-sandpit-client-key.pem -out redcap-sandpit-client-req.pem
Sign it
openssl x509 -req -in redcap-sandpit-client-req.pem \
-days 3650 \
-CA /etc/pki/tls/certs/mariadb-ca-cert.pem \
-CAkey /etc/pki/tls/private/mariadb-ca-key.pem \
-set_serial 02 \
-out redcap-sandpit-client-cert.pem
Set permissions,
chmod 0600 *key*
mariadb-ca-cert.pem
mariadb-ca-key.pem
mariadb-server-cert.pem
mariadb-server-key.pem
mariadb-server-req.pem
redcap-sandpit-client-key.pem
redcap-sandpit-client-req.pem
redcap-sandpit-client-cert.pem
Tar up the client and ca certs,
tar zcvf mariadb-ssl.tar.gz redcap-sandpit-client-key.pem mariadb-ca-key.pem redcap-sandpit-client-cert.pem
On the client,
Edit /var/www/html/database.php and disable the 5 lines as shown,
Add these to /etc/redcap/db_conn.php
/ Enable SSL
$db_ssl = true;
$db_ssl_key = '/etc/mysql/ssl/redcap-sandpit-client-key.pem';
$db_ssl_cert = '/etc/mysql/ssl/redcap-sandpit-client-cert.pem';
$db_ssl_ca = '/etc/mysql/ssl/mariadb-ca-key.pem';
$db_ssl_capath = null;
$db_ssl_cipher = null;
On the client,
(done in ansible incl selinux context) mkdir -p /etc/mariadb/ssl/ ; cd /etc/mariadb/ssl/
Copy and expand,
cp /home/vuw.ac.nz/admjonesst1/mariadb-ssl.tar.gz .
tar zxvf mariadb-ssl.tar.gz
Local test
mysql -u sandpit -p --ssl-ca=/etc/mariadb/ssl/mariadb-ca-cert.pem -h <ip address>
On Thu, 6 Aug 2026 at 16:46, dovecot--- via dovecot <dovecot@dovecot.org> wrote:
@basti require_secure_transport is OFF, I had checked that.
Hi Timo!
Creating the mysql-client.cnf didn't change the behavior, it tries to connect even with this minimal configuration:
/etc/dovecot/dovecot.conf: sql_driver = mysql
mysql host.docker.internal { option_file = /etc/dovecot/mysql-client.cnf }
/etc/dovecot/mysql-client.cnf: [client] ssl-mode=DISABLED
Still gets me an error: TLS/SSL error: self-signed certificate in certificate chain
In the meantime I will try to make it work using SSL. But the last time I tried it somehow conflicted with the "ssl_server_cert_file" and "ssl_server_key_file" which point to the certbot/letsencrypt certificates while MySQL generates self-signed certificates.
Thanks for your help so far!
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
Sorry to wander in in the middle of this but, Is the mysql server set to only take ssl?
In the database,
SHOW VARIABLES LIKE 'have_ssl';
or test with,
mysql -h <server> -u <user> -p --ssl-mode=DISABLED
Here are my notes for a mariadb ssl self cert but its very close for mysql, (and a different app but again should help)
to turn of,
[mariadb]
#ssl=0
and restart mysql/mariadb
Notes on making a ssl setup.
Mariadb/Mysql SSL/TLS
Thursday, 4 June 2026
12:45 pm
Database TLS
[1]https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/pdf/con...
[2]https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/html/configuring_and_using_database_servers/using-mysql#configuring-mysql
[3]https://docs.faveohelpdesk.com/docs/installation/providers/enterprise/redhat...
Database files,
ssl directory (set via ansible)
mkdir -p /var/lib/mysql/ssl
Create a Certificate Authority (CA)
cd /var/lib/mysql/ssl
# Generate CA private key
openssl genrsa 2048 > mariadb-ca-key.pem
Generate CA certificate
openssl req -new -x509 -nodes -days 3650 \
-key mariadb-ca-key.pem \
-out mariadb-ca-cert.pem
Generate Server Key and Certificate
Create server private key
openssl genrsa 2048 > mariadb-server-key.pem
Create certificate signing request (CSR)
openssl req -new -key mariadb-server-key.pem -out mariadb-server-req.pem
We now have 4 files,
mariadb-ca-cert.pem
mariadb-ca-key.pem
mariadb-server-key.pem
mariadb-server-req.pem
openssl x509 -req -in mariadb-server-req.pem \
-days 3650 \
-CA mariadb-ca-cert.pem \
-CAkey mariadb-ca-key.pem \
-set_serial 01 \
-out mariadb-server-cert.pem
We now have 5 files,
mariadb-ca-cert.pem
mariadb-ca-key.pem
mariadb-server-cert.pem
mariadb-server-key.pem
mariadb server-req.pem
Now do the sym links
ln -s /var/lib/mysql/ssl/mariadb-ca-key.pem /etc/pki/tls/private/mariadb-ca-key.pem ln -s /var/lib/mysql/ssl/mariadb-server-key.pem /etc/pki/tls/private/mariadb-server-key.pem
ln -s /var/lib/mysql/ssl/mariadb-ca-cert.pem /etc/pki/tls/certs/mariadb-ca-cert.pem
ln -s /var/lib/mysql/ssl/mariadb-server-cert.pem /etc/pki/tls/certs/mariadb-server-cert.pem
vi /etc/my.cnf.d/mariadb-server-tls.cnf
[mysqld]
ssl-ca=/path/to/ca.pem
ssl-cert=/path/to/server-cert.pem
ssl-key=/path/to/server-key.pem
[mariadb]
ssl_key = /var/lib/mysql/ssl/mariadb-server-key.pem
ssl_cert = /var/lib/mysql/ssl/mariadb-server-cert.pem
ssl_ca = /var/lib/mysql/ssl/mariadb-ca-key.pem
tls_version = TLSv1.3
#ssl=0
Verify the output hashes match,
openssl x509 -noout -modulus -in /etc/pki/tls/certs/mariadb-server-cert.pem | openssl md5 openssl rsa -noout -modulus -in /etc/pki/tls/private/mariadb-server-key.pem | openssl md5
Set ownership
chown mysql: *
Restart the database,
systemctl restart mysql
Check ssl is working,
SHOW VARIABLES LIKE 'have_ssl';
Check TLS version
mysql -u root -p
SHOW GLOBAL VARIABLES LIKE 'tls_version';
Other checks,
SHOW VARIABLES LIKE 'have_openssl';
SHOW STATUS LIKE 'Ssl_cipher';
Client side
cd /var/lib/mysql/ssl
# Client key
openssl genrsa 2048 > redcap-sandpit-client-key.pem
Client CSR
openssl req -new -key redcap-sandpit-client-key.pem -out redcap-sandpit-client-req.pem
Sign it
openssl x509 -req -in redcap-sandpit-client-req.pem \
-days 3650 \
-CA /etc/pki/tls/certs/mariadb-ca-cert.pem \
-CAkey /etc/pki/tls/private/mariadb-ca-key.pem \
-set_serial 02 \
-out redcap-sandpit-client-cert.pem
Set permissions,
chmod 0600 *key*
mariadb-ca-cert.pem
mariadb-ca-key.pem
mariadb-server-cert.pem
mariadb-server-key.pem
mariadb-server-req.pem
redcap-sandpit-client-key.pem
redcap-sandpit-client-req.pem
redcap-sandpit-client-cert.pem
Tar up the client and ca certs,
tar zcvf mariadb-ssl.tar.gz redcap-sandpit-client-key.pem mariadb-ca-key.pem redcap-sandpit-client-cert.pem
On the client,
Edit /var/www/html/database.php and disable the 5 lines as shown,
Add these to /etc/redcap/db_conn.php
/ Enable SSL
$db_ssl = true;
$db_ssl_key = '/etc/mysql/ssl/redcap-sandpit-client-key.pem';
$db_ssl_cert = '/etc/mysql/ssl/redcap-sandpit-client-cert.pem';
$db_ssl_ca = '/etc/mysql/ssl/mariadb-ca-key.pem';
$db_ssl_capath = null;
$db_ssl_cipher = null;
On the client,
(done in ansible incl selinux context) mkdir -p /etc/mariadb/ssl/ ; cd /etc/mariadb/ssl/
Copy and expand,
cp /home/[4]vuw.ac.nz/admjonesst1/mariadb-ssl.tar.gz .
tar zxvf mariadb-ssl.tar.gz
Local test
mysql -u sandpit -p --ssl-ca=/etc/mariadb/ssl/mariadb-ca-cert.pem -h
<ip address>
On Thu, 6 Aug 2026 at 16:46, dovecot--- via dovecot <[5]dovecot@dovecot.org> wrote:
@basti require_secure_transport is OFF, I had checked that.
Hi Timo!
Creating the mysql-client.cnf didn't change the behavior, it tries to
connect even with this minimal configuration:
/etc/dovecot/dovecot.conf:
sql_driver = mysql
mysql host.docker.internal {
option_file = /etc/dovecot/mysql-client.cnf
}
/etc/dovecot/mysql-client.cnf:
[client]
ssl-mode=DISABLED
Still gets me an error:
TLS/SSL error: self-signed certificate in certificate chain
In the meantime I will try to make it work using SSL. But the last time
I tried it somehow conflicted with the "ssl_server_cert_file" and
"ssl_server_key_file" which point to the certbot/letsencrypt
certificates while MySQL generates self-signed certificates.
Thanks for your help so far!
_______________________________________________
dovecot mailing list -- [6]dovecot@dovecot.org
To unsubscribe send an email to [7]dovecot-leave@dovecot.org
References
Visible links
- https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/pdf/con...
- https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/html/co...
- https://docs.faveohelpdesk.com/docs/installation/providers/enterprise/redhat...
- http://vuw.ac.nz/admjonesst1/mariadb-ssl.tar.gz
- mailto:dovecot@dovecot.org
- mailto:dovecot@dovecot.org
- mailto:dovecot-leave@dovecot.org
On 6. Aug 2026, at 0.47, dovecot--- via dovecot <dovecot@dovecot.org> wrote:
@basti require_secure_transport is OFF, I had checked that.
Hi Timo!
Creating the mysql-client.cnf didn't change the behavior, it tries to connect even with this minimal configuration:
/etc/dovecot/dovecot.conf: sql_driver = mysql
mysql host.docker.internal { option_file = /etc/dovecot/mysql-client.cnf }
/etc/dovecot/mysql-client.cnf: [client] ssl-mode=DISABLED
Still gets me an error: TLS/SSL error: self-signed certificate in certificate chain
Apparently this doesn't work with MariaDB library, and there's no workaround other than making the SSL cert work or disabling SSL on server side.
I got it to connect to my MySQL server using SSL. After looking into the code and understanding the option file (Google helped), I added the following option:
/etc/dovecot/mysql-client.cnf: [client] ssl-verify-server-cert=off
/etc/dovecot/dovecot.conf: mysql host.docker.internal { ssl = yes user = ... password = ... dbname = ... option_file = /etc/dovecot/mysql-client.cnf }
My MySQL server automatically generates certificates on startup, e.g. /var/lib/mysql/ca.pem
Those generated files contain a NUL char for whatever reason, which dovecot complains about. So I copied the file and removed the NUL char at the end. Then I set ssl_client_cert_file (within mysql) and pointed it to the new ca.pem. Then the error simply changed into "TLS/SSL error: unsupported". Funny enough, I could successfully test the connection within the docker container using openssl and the same ca.pem file dovecot was using. Open SSL reported that everything was fine.
So even though I couldn't make it verify the certificate, I could make it to connect which is enough for me at the moment.
Thank you all for your help!
participants (5)
-
Adam Miller
-
basti
-
dovecot@fagschlunger.at
-
Thing
-
Timo Sirainen