sqlx_mysql/options/
mod.rs

1use std::path::{Path, PathBuf};
2
3mod connect;
4mod parse;
5mod ssl_mode;
6
7use crate::{connection::LogSettings, net::tls::CertificateInput};
8pub use ssl_mode::MySqlSslMode;
9
10/// Options and flags which can be used to configure a MySQL connection.
11///
12/// A value of `MySqlConnectOptions` can be parsed from a connection URL,
13/// as described by [MySQL](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html).
14///
15/// The generic format of the connection URL:
16///
17/// ```text
18/// mysql://[host][/database][?properties]
19/// ```
20///
21/// This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string
22/// containing a connection URL and then further adjust options if necessary (see example below).
23///
24/// ## Properties
25///
26/// |Parameter|Default|Description|
27/// |---------|-------|-----------|
28/// | `ssl-mode` | `PREFERRED` | Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated. See [`MySqlSslMode`]. |
29/// | `ssl-ca` | `None` | Sets the name of a file containing a list of trusted SSL Certificate Authorities. |
30/// | `statement-cache-capacity` | `100` | The maximum number of prepared statements stored in the cache. Set to `0` to disable. |
31/// | `socket` | `None` | Path to the unix domain socket, which will be used instead of TCP if set. |
32///
33/// # Example
34///
35/// ```rust,no_run
36/// # async fn example() -> sqlx::Result<()> {
37/// use sqlx::{Connection, ConnectOptions};
38/// use sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode};
39///
40/// // URL connection string
41/// let conn = MySqlConnection::connect("mysql://root:password@localhost/db").await?;
42///
43/// // Manually-constructed options
44/// let conn = MySqlConnectOptions::new()
45///     .host("localhost")
46///     .username("root")
47///     .password("password")
48///     .database("db")
49///     .connect().await?;
50///
51/// // Modifying options parsed from a string
52/// let mut opts: MySqlConnectOptions = "mysql://root:password@localhost/db".parse()?;
53///
54/// // Change the log verbosity level for queries.
55/// // Information about SQL queries is logged at `DEBUG` level by default.
56/// opts = opts.log_statements(log::LevelFilter::Trace);
57///
58/// let pool = MySqlPool::connect_with(opts).await?;
59/// # Ok(())
60/// # }
61/// ```
62#[derive(Debug, Clone)]
63pub struct MySqlConnectOptions {
64    pub(crate) host: String,
65    pub(crate) port: u16,
66    pub(crate) socket: Option<PathBuf>,
67    pub(crate) username: String,
68    pub(crate) password: Option<String>,
69    pub(crate) database: Option<String>,
70    pub(crate) ssl_mode: MySqlSslMode,
71    pub(crate) ssl_ca: Option<CertificateInput>,
72    pub(crate) ssl_client_cert: Option<CertificateInput>,
73    pub(crate) ssl_client_key: Option<CertificateInput>,
74    pub(crate) statement_cache_capacity: usize,
75    pub(crate) charset: String,
76    pub(crate) collation: Option<String>,
77    pub(crate) log_settings: LogSettings,
78    pub(crate) pipes_as_concat: bool,
79    pub(crate) enable_cleartext_plugin: bool,
80    pub(crate) no_engine_substitution: bool,
81    pub(crate) timezone: Option<String>,
82    pub(crate) set_names: bool,
83}
84
85impl Default for MySqlConnectOptions {
86    fn default() -> Self {
87        Self::new()
88    }
89}
90
91impl MySqlConnectOptions {
92    /// Creates a new, default set of options ready for configuration
93    pub fn new() -> Self {
94        Self {
95            port: 3306,
96            host: String::from("localhost"),
97            socket: None,
98            username: String::from("root"),
99            password: None,
100            database: None,
101            charset: String::from("utf8mb4"),
102            collation: None,
103            ssl_mode: MySqlSslMode::Preferred,
104            ssl_ca: None,
105            ssl_client_cert: None,
106            ssl_client_key: None,
107            statement_cache_capacity: 100,
108            log_settings: Default::default(),
109            pipes_as_concat: true,
110            enable_cleartext_plugin: false,
111            no_engine_substitution: true,
112            timezone: Some(String::from("+00:00")),
113            set_names: true,
114        }
115    }
116
117    /// Sets the name of the host to connect to.
118    ///
119    /// The default behavior when the host is not specified,
120    /// is to connect to localhost.
121    pub fn host(mut self, host: &str) -> Self {
122        host.clone_into(&mut self.host);
123        self
124    }
125
126    /// Sets the port to connect to at the server host.
127    ///
128    /// The default port for MySQL is `3306`.
129    pub fn port(mut self, port: u16) -> Self {
130        self.port = port;
131        self
132    }
133
134    /// Pass a path to a Unix socket. This changes the connection stream from
135    /// TCP to UDS.
136    ///
137    /// By default set to `None`.
138    pub fn socket(mut self, path: impl AsRef<Path>) -> Self {
139        self.socket = Some(path.as_ref().to_path_buf());
140        self
141    }
142
143    /// Sets the username to connect as.
144    pub fn username(mut self, username: &str) -> Self {
145        username.clone_into(&mut self.username);
146        self
147    }
148
149    /// Sets the password to connect with.
150    pub fn password(mut self, password: &str) -> Self {
151        self.password = Some(password.to_owned());
152        self
153    }
154
155    /// Sets the database name.
156    pub fn database(mut self, database: &str) -> Self {
157        self.database = Some(database.to_owned());
158        self
159    }
160
161    /// Sets whether or with what priority a secure SSL TCP/IP connection will be negotiated
162    /// with the server.
163    ///
164    /// By default, the SSL mode is [`Preferred`](MySqlSslMode::Preferred), and the client will
165    /// first attempt an SSL connection but fallback to a non-SSL connection on failure.
166    ///
167    /// # Example
168    ///
169    /// ```rust
170    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
171    /// let options = MySqlConnectOptions::new()
172    ///     .ssl_mode(MySqlSslMode::Required);
173    /// ```
174    pub fn ssl_mode(mut self, mode: MySqlSslMode) -> Self {
175        self.ssl_mode = mode;
176        self
177    }
178
179    /// Sets the name of a file containing a list of trusted SSL Certificate Authorities.
180    ///
181    /// # Example
182    ///
183    /// ```rust
184    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
185    /// let options = MySqlConnectOptions::new()
186    ///     .ssl_mode(MySqlSslMode::VerifyCa)
187    ///     .ssl_ca("path/to/ca.crt");
188    /// ```
189    pub fn ssl_ca(mut self, file_name: impl AsRef<Path>) -> Self {
190        self.ssl_ca = Some(CertificateInput::File(file_name.as_ref().to_owned()));
191        self
192    }
193
194    /// Sets PEM encoded list of trusted SSL Certificate Authorities.
195    ///
196    /// # Example
197    ///
198    /// ```rust
199    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
200    /// let options = MySqlConnectOptions::new()
201    ///     .ssl_mode(MySqlSslMode::VerifyCa)
202    ///     .ssl_ca_from_pem(vec![]);
203    /// ```
204    pub fn ssl_ca_from_pem(mut self, pem_certificate: Vec<u8>) -> Self {
205        self.ssl_ca = Some(CertificateInput::Inline(pem_certificate));
206        self
207    }
208
209    /// Sets the name of a file containing SSL client certificate.
210    ///
211    /// # Example
212    ///
213    /// ```rust
214    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
215    /// let options = MySqlConnectOptions::new()
216    ///     .ssl_mode(MySqlSslMode::VerifyCa)
217    ///     .ssl_client_cert("path/to/client.crt");
218    /// ```
219    pub fn ssl_client_cert(mut self, cert: impl AsRef<Path>) -> Self {
220        self.ssl_client_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf()));
221        self
222    }
223
224    /// Sets the SSL client certificate as a PEM-encoded byte slice.
225    ///
226    /// This should be an ASCII-encoded blob that starts with `-----BEGIN CERTIFICATE-----`.
227    ///
228    /// # Example
229    /// Note: embedding SSL certificates and keys in the binary is not advised.
230    /// This is for illustration purposes only.
231    ///
232    /// ```rust
233    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
234    ///
235    /// const CERT: &[u8] = b"\
236    /// -----BEGIN CERTIFICATE-----
237    /// <Certificate data here.>
238    /// -----END CERTIFICATE-----";
239    ///
240    /// let options = MySqlConnectOptions::new()
241    ///     .ssl_mode(MySqlSslMode::VerifyCa)
242    ///     .ssl_client_cert_from_pem(CERT);
243    /// ```
244    pub fn ssl_client_cert_from_pem(mut self, cert: impl AsRef<[u8]>) -> Self {
245        self.ssl_client_cert = Some(CertificateInput::Inline(cert.as_ref().to_vec()));
246        self
247    }
248
249    /// Sets the name of a file containing SSL client key.
250    ///
251    /// # Example
252    ///
253    /// ```rust
254    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
255    /// let options = MySqlConnectOptions::new()
256    ///     .ssl_mode(MySqlSslMode::VerifyCa)
257    ///     .ssl_client_key("path/to/client.key");
258    /// ```
259    pub fn ssl_client_key(mut self, key: impl AsRef<Path>) -> Self {
260        self.ssl_client_key = Some(CertificateInput::File(key.as_ref().to_path_buf()));
261        self
262    }
263
264    /// Sets the SSL client key as a PEM-encoded byte slice.
265    ///
266    /// This should be an ASCII-encoded blob that starts with `-----BEGIN PRIVATE KEY-----`.
267    ///
268    /// # Example
269    /// Note: embedding SSL certificates and keys in the binary is not advised.
270    /// This is for illustration purposes only.
271    ///
272    /// ```rust
273    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};
274    ///
275    /// const KEY: &[u8] = b"\
276    /// -----BEGIN PRIVATE KEY-----
277    /// <Private key data here.>
278    /// -----END PRIVATE KEY-----";
279    ///
280    /// let options = MySqlConnectOptions::new()
281    ///     .ssl_mode(MySqlSslMode::VerifyCa)
282    ///     .ssl_client_key_from_pem(KEY);
283    /// ```
284    pub fn ssl_client_key_from_pem(mut self, key: impl AsRef<[u8]>) -> Self {
285        self.ssl_client_key = Some(CertificateInput::Inline(key.as_ref().to_vec()));
286        self
287    }
288
289    /// Sets the capacity of the connection's statement cache in a number of stored
290    /// distinct statements. Caching is handled using LRU, meaning when the
291    /// amount of queries hits the defined limit, the oldest statement will get
292    /// dropped.
293    ///
294    /// The default cache capacity is 100 statements.
295    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {
296        self.statement_cache_capacity = capacity;
297        self
298    }
299
300    /// Sets the character set for the connection.
301    ///
302    /// The default character set is `utf8mb4`. This is supported from MySQL 5.5.3.
303    /// If you need to connect to an older version, we recommend you to change this to `utf8`.
304    pub fn charset(mut self, charset: &str) -> Self {
305        charset.clone_into(&mut self.charset);
306        self
307    }
308
309    /// Sets the collation for the connection.
310    ///
311    /// The default collation is derived from the `charset`. Normally, you should only have to set
312    /// the `charset`.
313    pub fn collation(mut self, collation: &str) -> Self {
314        self.collation = Some(collation.to_owned());
315        self
316    }
317
318    /// Sets the flag that enables or disables the `PIPES_AS_CONCAT` connection setting
319    ///
320    /// The default value is set to true, but some MySql databases such as PlanetScale
321    /// error out with this connection setting so it needs to be set false in such
322    /// cases.
323    pub fn pipes_as_concat(mut self, flag_val: bool) -> Self {
324        self.pipes_as_concat = flag_val;
325        self
326    }
327
328    /// Enables mysql_clear_password plugin support.
329    ///
330    /// Security Note:
331    /// Sending passwords as cleartext may be a security problem in some
332    /// configurations. Without additional defensive configuration like
333    /// ssl-mode=VERIFY_IDENTITY, an attacker can compromise a router
334    /// and trick the application into divulging its credentials.
335    ///
336    /// It is strongly recommended to set `.ssl_mode` to `Required`,
337    /// `VerifyCa`, or `VerifyIdentity` when enabling cleartext plugin.
338    pub fn enable_cleartext_plugin(mut self, flag_val: bool) -> Self {
339        self.enable_cleartext_plugin = flag_val;
340        self
341    }
342
343    #[deprecated = "renamed to .no_engine_substitution()"]
344    pub fn no_engine_subsitution(self, flag_val: bool) -> Self {
345        self.no_engine_substitution(flag_val)
346    }
347
348    /// Flag that enables or disables the `NO_ENGINE_SUBSTITUTION` sql_mode setting after
349    /// connection.
350    ///
351    /// If not set, if the available storage engine specified by a `CREATE TABLE` is not available,
352    /// a warning is given and the default storage engine is used instead.
353    ///
354    /// By default, this is `true` (`NO_ENGINE_SUBSTITUTION` is passed, forbidding engine
355    /// substitution).
356    ///
357    /// <https://mariadb.com/kb/en/sql-mode/>
358    pub fn no_engine_substitution(mut self, flag_val: bool) -> Self {
359        self.no_engine_substitution = flag_val;
360        self
361    }
362
363    /// If `Some`, sets the `time_zone` option to the given string after connecting to the database.
364    ///
365    /// If `None`, no `time_zone` parameter is sent; the server timezone will be used instead.
366    ///
367    /// Defaults to `Some(String::from("+00:00"))` to ensure all timestamps are in UTC.
368    ///
369    /// ### Warning
370    /// Changing this setting from its default will apply an unexpected skew to any
371    /// `time::OffsetDateTime` or `chrono::DateTime<Utc>` value, whether passed as a parameter or
372    /// decoded as a result. `TIMESTAMP` values are not encoded with their UTC offset in the MySQL
373    /// protocol, so encoding and decoding of these types assumes the server timezone is *always*
374    /// UTC.
375    ///
376    /// If you are changing this option, ensure your application only uses
377    /// `time::PrimitiveDateTime` or `chrono::NaiveDateTime` and that it does not assume these
378    /// timestamps can be placed on a real timeline without applying the proper offset.
379    pub fn timezone(mut self, value: impl Into<Option<String>>) -> Self {
380        self.timezone = value.into();
381        self
382    }
383
384    /// If enabled, `SET NAMES '{charset}' COLLATE '{collation}'` is passed with the values of
385    /// [`.charset()`] and [`.collation()`] after connecting to the database.
386    ///
387    /// This ensures the connection uses the specified character set and collation.
388    ///
389    /// Enabled by default.
390    ///
391    /// ### Warning
392    /// If this is disabled and the default charset is not binary-compatible with UTF-8, query
393    /// strings, column names and string values will likely not decode (or encode) correctly, which
394    /// may result in unexpected errors or garbage outputs at runtime.
395    ///
396    /// For proper functioning, you *must* ensure the server is using a binary-compatible charset,
397    /// such as ASCII or Latin-1 (ISO 8859-1), and that you do not pass any strings containing
398    /// codepoints not supported by said charset.
399    ///
400    /// Instead of disabling this, you may also consider setting [`.charset()`] to a charset that
401    /// is supported by your MySQL or MariaDB server version and compatible with UTF-8.
402    pub fn set_names(mut self, flag_val: bool) -> Self {
403        self.set_names = flag_val;
404        self
405    }
406}
407
408impl MySqlConnectOptions {
409    /// Get the current host.
410    ///
411    /// # Example
412    ///
413    /// ```rust
414    /// # use sqlx_mysql::MySqlConnectOptions;
415    /// let options = MySqlConnectOptions::new()
416    ///     .host("127.0.0.1");
417    /// assert_eq!(options.get_host(), "127.0.0.1");
418    /// ```
419    pub fn get_host(&self) -> &str {
420        &self.host
421    }
422
423    /// Get the server's port.
424    ///
425    /// # Example
426    ///
427    /// ```rust
428    /// # use sqlx_mysql::MySqlConnectOptions;
429    /// let options = MySqlConnectOptions::new()
430    ///     .port(6543);
431    /// assert_eq!(options.get_port(), 6543);
432    /// ```
433    pub fn get_port(&self) -> u16 {
434        self.port
435    }
436
437    /// Get the socket path.
438    ///
439    /// # Example
440    ///
441    /// ```rust
442    /// # use sqlx_mysql::MySqlConnectOptions;
443    /// let options = MySqlConnectOptions::new()
444    ///     .socket("/tmp");
445    /// assert!(options.get_socket().is_some());
446    /// ```
447    pub fn get_socket(&self) -> Option<&PathBuf> {
448        self.socket.as_ref()
449    }
450
451    /// Get the server's port.
452    ///
453    /// # Example
454    ///
455    /// ```rust
456    /// # use sqlx_mysql::MySqlConnectOptions;
457    /// let options = MySqlConnectOptions::new()
458    ///     .username("foo");
459    /// assert_eq!(options.get_username(), "foo");
460    /// ```
461    pub fn get_username(&self) -> &str {
462        &self.username
463    }
464
465    /// Get the current database name.
466    ///
467    /// # Example
468    ///
469    /// ```rust
470    /// # use sqlx_mysql::MySqlConnectOptions;
471    /// let options = MySqlConnectOptions::new()
472    ///     .database("postgres");
473    /// assert!(options.get_database().is_some());
474    /// ```
475    pub fn get_database(&self) -> Option<&str> {
476        self.database.as_deref()
477    }
478
479    /// Get the SSL mode.
480    ///
481    /// # Example
482    ///
483    /// ```rust
484    /// # use sqlx_mysql::{MySqlConnectOptions, MySqlSslMode};
485    /// let options = MySqlConnectOptions::new();
486    /// assert!(matches!(options.get_ssl_mode(), MySqlSslMode::Preferred));
487    /// ```
488    pub fn get_ssl_mode(&self) -> MySqlSslMode {
489        self.ssl_mode
490    }
491
492    /// Get the server charset.
493    ///
494    /// # Example
495    ///
496    /// ```rust
497    /// # use sqlx_mysql::MySqlConnectOptions;
498    /// let options = MySqlConnectOptions::new();
499    /// assert_eq!(options.get_charset(), "utf8mb4");
500    /// ```
501    pub fn get_charset(&self) -> &str {
502        &self.charset
503    }
504
505    /// Get the server collation.
506    ///
507    /// # Example
508    ///
509    /// ```rust
510    /// # use sqlx_mysql::MySqlConnectOptions;
511    /// let options = MySqlConnectOptions::new()
512    ///     .collation("collation");
513    /// assert!(options.get_collation().is_some());
514    /// ```
515    pub fn get_collation(&self) -> Option<&str> {
516        self.collation.as_deref()
517    }
518}