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