diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml
index d583f33d..229c2485 100644
--- a/.github/workflows/sqlx.yml
+++ b/.github/workflows/sqlx.yml
@@ -32,7 +32,8 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     steps:
       - uses: actions/checkout@v2
 
@@ -48,7 +49,7 @@ jobs:
             ~/.cargo/registry
             ~/.cargo/git
             target
-          key: ${{ runner.os }}-check-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
+          key: ${{ runner.os }}-check-${{ matrix.runtime }}-${{ matrix.tls }}-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/cargo@v1
         with:
@@ -56,21 +57,22 @@ jobs:
           args: >
             --manifest-path sqlx-core/Cargo.toml
             --no-default-features
-            --features offline,all-databases,all-types,migrate,runtime-${{ matrix.runtime }}
+            --features offline,all-databases,all-types,migrate,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
 
       - uses: actions-rs/cargo@v1
         with:
           command: check
           args: >
             --no-default-features
-            --features offline,all-databases,all-types,migrate,runtime-${{ matrix.runtime }},macros
+            --features offline,all-databases,all-types,migrate,runtime-${{ matrix.runtime }}-${{ matrix.tls }},macros
 
   test:
     name: Unit Test
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     steps:
       - uses: actions/checkout@v2
 
@@ -93,7 +95,7 @@ jobs:
           command: test
           args: >
             --manifest-path sqlx-core/Cargo.toml
-            --features offline,all-databases,all-types,runtime-${{ matrix.runtime }}
+            --features offline,all-databases,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
 
   cli:
     name: CLI Binaries
@@ -148,7 +150,8 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     needs: check
     steps:
       - uses: actions/checkout@v2
@@ -165,14 +168,14 @@ jobs:
             ~/.cargo/registry
             ~/.cargo/git
             target
-          key: ${{ runner.os }}-sqlite-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
+          key: ${{ runner.os }}-sqlite-${{ matrix.runtime }}-${{ matrix.tls }}-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/cargo@v1
         with:
           command: test
           args: >
             --no-default-features
-            --features any,macros,migrate,sqlite,all-types,runtime-${{ matrix.runtime }}
+            --features any,macros,migrate,sqlite,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
             --
             --test-threads=1
         env:
@@ -183,8 +186,9 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        postgres: [12, 10, 9_6, 9_5]
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        postgres: [13, 9_6]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     needs: check
     steps:
       - uses: actions/checkout@v2
@@ -201,23 +205,24 @@ jobs:
             ~/.cargo/registry
             ~/.cargo/git
             target
-          key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
+          key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ matrix.tls }}-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/cargo@v1
         with:
           command: build
           args: >
-            --features postgres,all-types,runtime-${{ matrix.runtime }}
+            --features postgres,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
 
-      - run: docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 postgres_${{ matrix.postgres }}
-      - run: sleep 10
+      - run: |
+          docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }} postgres_${{ matrix.postgres }}
+          docker exec postgres_${{ matrix.postgres }} bash -c "until pg_isready; do sleep 1; done"
 
       - uses: actions-rs/cargo@v1
         with:
           command: test
           args: >
             --no-default-features
-            --features any,postgres,macros,all-types,runtime-${{ matrix.runtime }}
+            --features any,postgres,macros,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
         env:
           DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx
 
@@ -226,7 +231,7 @@ jobs:
           command: test
           args: >
             --no-default-features
-            --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }}
+            --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
         env:
           DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt
 
@@ -235,8 +240,9 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        mysql: [8, 5_7, 5_6]
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        mysql: [8, 5_6]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     needs: check
     steps:
       - uses: actions/checkout@v2
@@ -253,13 +259,13 @@ jobs:
             ~/.cargo/registry
             ~/.cargo/git
             target
-          key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
+          key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }}-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/cargo@v1
         with:
           command: build
           args: >
-            --features mysql,all-types,runtime-${{ matrix.runtime }}
+            --features mysql,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
 
       - run: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}
       - run: sleep 60
@@ -269,7 +275,7 @@ jobs:
           command: test
           args: >
             --no-default-features
-            --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}
+            --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
         env:
           DATABASE_URL: mysql://root:password@localhost:3306/sqlx
 
@@ -278,8 +284,9 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        mariadb: [10_5, 10_4, 10_3, 10_2, 10_1]
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        mariadb: [10_6, 10_2]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     needs: check
     steps:
       - uses: actions/checkout@v2
@@ -297,13 +304,13 @@ jobs:
             ~/.cargo/registry
             ~/.cargo/git
             target
-          key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
+          key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }}-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/cargo@v1
         with:
           command: build
           args: >
-            --features mysql,all-types,runtime-${{ matrix.runtime }}
+            --features mysql,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
 
       - run: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mariadb_${{ matrix.mariadb }}
       - run: sleep 30
@@ -313,7 +320,7 @@ jobs:
           command: test
           args: >
             --no-default-features
-            --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}
+            --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
         env:
           DATABASE_URL: mysql://root:password@localhost:3306/sqlx
 
@@ -322,8 +329,9 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        mssql: [2019]
-        runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls, async-std-rustls, tokio-rustls, actix-rustls]
+        mssql: [2019, 2017]
+        runtime: [async-std, tokio, actix]
+        tls: [native-tls, rustls]
     needs: check
     steps:
       - uses: actions/checkout@v2
@@ -340,13 +348,13 @@ jobs:
             ~/.cargo/registry
             ~/.cargo/git
             target
-          key: ${{ runner.os }}-mssql-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
+          key: ${{ runner.os }}-mssql-${{ matrix.runtime }}-${{ matrix.tls }}-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/cargo@v1
         with:
           command: build
           args: >
-            --features mssql,all-types,runtime-${{ matrix.runtime }}
+            --features mssql,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
 
       - run: docker-compose -f tests/docker-compose.yml run -d -p 1433:1433 mssql_${{ matrix.mssql }}
       - run: sleep 80 # MSSQL takes a "bit" to startup
@@ -356,6 +364,6 @@ jobs:
           command: test
           args: >
             --no-default-features
-            --features any,mssql,macros,migrate,all-types,runtime-${{ matrix.runtime }}
+            --features any,mssql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }}
         env:
           DATABASE_URL: mssql://sa:Password123!@localhost/sqlx
diff --git a/sqlx-core/src/postgres/connection/mod.rs b/sqlx-core/src/postgres/connection/mod.rs
index e0238f59..ea49a532 100644
--- a/sqlx-core/src/postgres/connection/mod.rs
+++ b/sqlx-core/src/postgres/connection/mod.rs
@@ -177,3 +177,20 @@ impl Connection for PgConnection {
         !self.stream.wbuf.is_empty()
     }
 }
+
+pub trait PgConnectionInfo {
+    /// the version number of the server in `libpq` format
+    fn server_version_num(&self) -> Option<u32>;
+}
+
+impl PgConnectionInfo for PgConnection {
+    fn server_version_num(&self) -> Option<u32> {
+        self.stream.server_version_num
+    }
+}
+
+impl PgConnectionInfo for crate::pool::PoolConnection<Postgres> {
+    fn server_version_num(&self) -> Option<u32> {
+        self.stream.server_version_num
+    }
+}
diff --git a/sqlx-core/src/postgres/connection/stream.rs b/sqlx-core/src/postgres/connection/stream.rs
index f61bda62..950d8d09 100644
--- a/sqlx-core/src/postgres/connection/stream.rs
+++ b/sqlx-core/src/postgres/connection/stream.rs
@@ -1,4 +1,6 @@
+use std::collections::BTreeMap;
 use std::ops::{Deref, DerefMut};
+use std::str::FromStr;
 
 use bytes::{Buf, Bytes};
 use futures_channel::mpsc::UnboundedSender;
@@ -8,7 +10,7 @@ use log::Level;
 use crate::error::Error;
 use crate::io::{BufStream, Decode, Encode};
 use crate::net::{MaybeTlsStream, Socket};
-use crate::postgres::message::{Message, MessageFormat, Notice, Notification};
+use crate::postgres::message::{Message, MessageFormat, Notice, Notification, ParameterStatus};
 use crate::postgres::{PgConnectOptions, PgDatabaseError, PgSeverity};
 
 // the stream is a separate type from the connection to uphold the invariant where an instantiated
@@ -27,6 +29,10 @@ pub struct PgStream {
     // this is set when creating a PgListener and only written to if that listener is
     // re-used for query execution in-between receiving messages
     pub(crate) notifications: Option<UnboundedSender<Notification>>,
+
+    pub(crate) parameter_statuses: BTreeMap<String, String>,
+
+    pub(crate) server_version_num: Option<u32>,
 }
 
 impl PgStream {
@@ -41,6 +47,8 @@ impl PgStream {
         Ok(Self {
             inner,
             notifications: None,
+            parameter_statuses: BTreeMap::default(),
+            server_version_num: None,
         })
     }
 
@@ -108,7 +116,18 @@ impl PgStream {
                     // informs the frontend about the current (initial)
                     // setting of backend parameters
 
-                    // we currently have no use for that data so we promptly ignore this message
+                    let ParameterStatus { name, value } = message.decode()?;
+                    // TODO: handle `client_encoding`, `DateStyle` change
+
+                    match name.as_str() {
+                        "server_version" => {
+                            self.server_version_num = parse_server_version(&value);
+                        }
+                        _ => {
+                            self.parameter_statuses.insert(name, value);
+                        }
+                    }
+
                     continue;
                 }
 
@@ -165,3 +184,68 @@ impl DerefMut for PgStream {
         &mut self.inner
     }
 }
+
+// reference:
+// https://github.com/postgres/postgres/blob/6feebcb6b44631c3dc435e971bd80c2dd218a5ab/src/interfaces/libpq/fe-exec.c#L1030-L1065
+fn parse_server_version(s: &str) -> Option<u32> {
+    let mut parts = Vec::<u32>::with_capacity(3);
+
+    let mut from = 0;
+    let mut chs = s.char_indices().peekable();
+    while let Some((i, ch)) = chs.next() {
+        match ch {
+            '.' => {
+                if let Ok(num) = u32::from_str(&s[from..i]) {
+                    parts.push(num);
+                    from = i + 1;
+                } else {
+                    break;
+                }
+            }
+            _ if ch.is_digit(10) => {
+                if chs.peek().is_none() {
+                    if let Ok(num) = u32::from_str(&s[from..]) {
+                        parts.push(num);
+                    }
+                    break;
+                }
+            }
+            _ => {
+                if let Ok(num) = u32::from_str(&s[from..i]) {
+                    parts.push(num);
+                }
+                break;
+            }
+        };
+    }
+
+    let version_num = match parts.as_slice() {
+        [major, minor, rev] => (100 * major + minor) * 100 + rev,
+        [major, minor] if *major >= 10 => 100 * 100 * major + minor,
+        [major, minor] => (100 * major + minor) * 100,
+        [major] => 100 * 100 * major,
+        _ => return None,
+    };
+
+    Some(version_num)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::parse_server_version;
+
+    #[test]
+    fn test_parse_server_version_num() {
+        // old style
+        assert_eq!(parse_server_version("9.6.1"), Some(90601));
+        // new style
+        assert_eq!(parse_server_version("10.1"), Some(100001));
+        // old style without minor version
+        assert_eq!(parse_server_version("9.6devel"), Some(90600));
+        // new style without minor version, e.g.  */
+        assert_eq!(parse_server_version("10devel"), Some(100000));
+        assert_eq!(parse_server_version("13devel87"), Some(130000));
+        // unknown
+        assert_eq!(parse_server_version("unknown"), None);
+    }
+}
diff --git a/sqlx-core/src/postgres/message/mod.rs b/sqlx-core/src/postgres/message/mod.rs
index 6c8d1f30..91aa5789 100644
--- a/sqlx-core/src/postgres/message/mod.rs
+++ b/sqlx-core/src/postgres/message/mod.rs
@@ -14,6 +14,7 @@ mod execute;
 mod flush;
 mod notification;
 mod parameter_description;
+mod parameter_status;
 mod parse;
 mod password;
 mod query;
@@ -37,6 +38,7 @@ pub use execute::Execute;
 pub use flush::Flush;
 pub use notification::Notification;
 pub use parameter_description::ParameterDescription;
+pub use parameter_status::ParameterStatus;
 pub use parse::Parse;
 pub use password::Password;
 pub use query::Query;
diff --git a/sqlx-core/src/postgres/message/parameter_status.rs b/sqlx-core/src/postgres/message/parameter_status.rs
new file mode 100644
index 00000000..d5428d18
--- /dev/null
+++ b/sqlx-core/src/postgres/message/parameter_status.rs
@@ -0,0 +1,49 @@
+use bytes::Bytes;
+
+use crate::error::Error;
+use crate::io::{BufExt, Decode};
+
+#[derive(Debug)]
+pub struct ParameterStatus {
+    pub name: String,
+    pub value: String,
+}
+
+impl Decode<'_> for ParameterStatus {
+    fn decode_with(mut buf: Bytes, _: ()) -> Result<Self, Error> {
+        let name = buf.get_str_nul()?;
+        let value = buf.get_str_nul()?;
+
+        Ok(Self { name, value })
+    }
+}
+
+#[test]
+fn test_decode_parameter_status() {
+    const DATA: &[u8] = b"client_encoding\x00UTF8\x00";
+
+    let m = ParameterStatus::decode(DATA.into()).unwrap();
+
+    assert_eq!(&m.name, "client_encoding");
+    assert_eq!(&m.value, "UTF8")
+}
+
+#[test]
+fn test_decode_empty_parameter_status() {
+    const DATA: &[u8] = b"\x00\x00";
+
+    let m = ParameterStatus::decode(DATA.into()).unwrap();
+
+    assert!(m.name.is_empty());
+    assert!(m.value.is_empty());
+}
+
+#[cfg(all(test, not(debug_assertions)))]
+#[bench]
+fn bench_decode_parameter_status(b: &mut test::Bencher) {
+    const DATA: &[u8] = b"client_encoding\x00UTF8\x00";
+
+    b.iter(|| {
+        ParameterStatus::decode(test::black_box(Bytes::from_static(DATA))).unwrap();
+    });
+}
diff --git a/sqlx-core/src/postgres/mod.rs b/sqlx-core/src/postgres/mod.rs
index bd72bc6e..ed6af06a 100644
--- a/sqlx-core/src/postgres/mod.rs
+++ b/sqlx-core/src/postgres/mod.rs
@@ -22,7 +22,7 @@ mod migrate;
 
 pub use arguments::{PgArgumentBuffer, PgArguments};
 pub use column::PgColumn;
-pub use connection::PgConnection;
+pub use connection::{PgConnection, PgConnectionInfo};
 pub use database::Postgres;
 pub use error::{PgDatabaseError, PgErrorPosition};
 pub use listener::{PgListener, PgNotification};
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 00000000..bc2dc232
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,18 @@
+
+
+### Running Tests
+SQLx uses docker to run many compatible database systems for integration testing. You'll need to [install docker](https://docs.docker.com/engine/) to run the full suite. You can validate your docker installation with:
+    
+    $ docker run hello-world
+
+Start the databases with `docker-compose` before running tests: 
+
+    $ docker-compose up
+
+Run all tests against all supported databases using:
+
+    $ ./x.py
+
+If you see test failures, or want to run a more specific set of tests against a specific database, you can specify both the features to be tests and the DATABASE_URL. e.g.
+
+    $ DATABASE_URL=mysql://root:password@127.0.0.1:49183/sqlx cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-async-std-native-tls
diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml
index 4d0e3984..30203b17 100644
--- a/tests/docker-compose.yml
+++ b/tests/docker-compose.yml
@@ -2,7 +2,7 @@ version: "3"
 
 services:
     #
-    # MySQL 5.6.x, 5.7.x, 8.x
+    # MySQL 8.x, 5.7.x, 5.6.x
     # https://www.mysql.com/support/supportedplatforms/database.html
     #
 
@@ -40,10 +40,20 @@ services:
             MYSQL_DATABASE: sqlx
 
     #
-    # MariaDB 10.5, 10.4, 10.3, 10.2, 10.1
+    # MariaDB 10.6, 10.5, 10.4, 10.3, 10.2
     # https://mariadb.org/about/#maintenance-policy
     #
 
+    mariadb_10_6:
+        image: mariadb:10.6
+        volumes:
+            - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql"
+        ports:
+            - 3306
+        environment:
+            MYSQL_ROOT_PASSWORD: password
+            MYSQL_DATABASE: sqlx
+
     mariadb_10_5:
         image: mariadb:10.5
         volumes:
@@ -84,27 +94,36 @@ services:
             MYSQL_ROOT_PASSWORD: password
             MYSQL_DATABASE: sqlx
 
-    mariadb_10_1:
-        image: mariadb:10.1
-        volumes:
-            - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql"
-        ports:
-            - 3306
-        environment:
-            MYSQL_ROOT_PASSWORD: password
-            MYSQL_DATABASE: sqlx
-
     #
-    # PostgreSQL 12.x, 10.x, 9.6.x, 9.5.x
+    # PostgreSQL 13.x, 12.x, 11.x 10.x, 9.6.x
     # https://www.postgresql.org/support/versioning/
     #
 
+    postgres_14:
+        build:
+            context: .
+            dockerfile: postgres/Dockerfile
+            args:
+              VERSION: 14beta2
+        ports:
+            - 5432
+        environment:
+            POSTGRES_DB: sqlx
+            POSTGRES_USER: postgres
+            POSTGRES_PASSWORD: password
+            POSTGRES_HOST_AUTH_METHOD: scram-sha-256
+            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256
+        volumes:
+            - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql"
+        command: >
+            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
+
     postgres_13:
         build:
             context: .
             dockerfile: postgres/Dockerfile
             args:
-                VERSION: 13-beta1
+              VERSION: 13
         ports:
             - 5432
         environment:
@@ -123,7 +142,7 @@ services:
             context: .
             dockerfile: postgres/Dockerfile
             args:
-              VERSION: 12.3
+              VERSION: 12
         ports:
             - 5432
         environment:
@@ -137,19 +156,39 @@ services:
         command: >
             -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
 
+    postgres_11:
+        build:
+            context: .
+            dockerfile: postgres/Dockerfile
+            args:
+                VERSION: 11
+        ports:
+          - 5432
+        environment:
+            POSTGRES_DB: sqlx
+            POSTGRES_USER: postgres
+            POSTGRES_PASSWORD: password
+            POSTGRES_HOST_AUTH_METHOD: scram-sha-256
+            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256
+        volumes:
+            - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql"
+        command: >
+            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
+
     postgres_10:
         build:
             context: .
             dockerfile: postgres/Dockerfile
             args:
-                VERSION: 10.13
+                VERSION: 10
         ports:
           - 5432
         environment:
             POSTGRES_DB: sqlx
             POSTGRES_USER: postgres
             POSTGRES_PASSWORD: password
-            POSTGRES_HOST_AUTH_METHOD: trust
+            POSTGRES_HOST_AUTH_METHOD: scram-sha-256
+            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256
         volumes:
             - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql"
         command: >
@@ -173,24 +212,6 @@ services:
         command: >
             -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
 
-    postgres_9_5:
-        build:
-            context: .
-            dockerfile: postgres/Dockerfile
-            args:
-                VERSION: 9.5
-        ports:
-          - 5432
-        environment:
-            POSTGRES_DB: sqlx
-            POSTGRES_USER: postgres
-            POSTGRES_PASSWORD: password
-            POSTGRES_HOST_AUTH_METHOD: password
-        volumes:
-            - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql"
-        command: >
-            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
-
     #
     # Microsoft SQL Server (MSSQL)
     # https://hub.docker.com/_/microsoft-mssql-server
@@ -205,17 +226,17 @@ services:
         ports:
           - 1433
         environment:
-            ACCEPT_EULA: Y
+            ACCEPT_EULA: "Y"
             SA_PASSWORD: Password123!
 
     mssql_2017:
         build:
             context: .
-            dockerfile: mssql/Dockerfile
+            dockerfile: mssql/mssql-2017.dockerfile
             args:
                 VERSION: 2017-latest
         environment:
-            ACCEPT_EULA: Y
+            ACCEPT_EULA: "Y"
             SA_PASSWORD: Password123!
 
     #
diff --git a/tests/docker.py b/tests/docker.py
index b4cdadd6..e664c38c 100644
--- a/tests/docker.py
+++ b/tests/docker.py
@@ -1,4 +1,5 @@
 import subprocess
+import sys
 import time
 from os import path
 
diff --git a/tests/mssql/mssql-2017.dockerfile b/tests/mssql/mssql-2017.dockerfile
new file mode 100644
index 00000000..a2e0b58d
--- /dev/null
+++ b/tests/mssql/mssql-2017.dockerfile
@@ -0,0 +1,19 @@
+# vim: set ft=dockerfile:
+ARG VERSION
+FROM mcr.microsoft.com/mssql/server:${VERSION}
+
+# Create a config directory
+RUN mkdir -p /usr/config
+WORKDIR /usr/config
+
+# Bundle config source
+COPY mssql/entrypoint.sh /usr/config/entrypoint.sh
+COPY mssql/configure-db.sh /usr/config/configure-db.sh
+COPY mssql/setup.sql /usr/config/setup.sql
+
+# Grant permissions for to our scripts to be executable
+USER root
+RUN chmod +x /usr/config/entrypoint.sh
+RUN chmod +x /usr/config/configure-db.sh
+
+ENTRYPOINT ["/usr/config/entrypoint.sh"]
diff --git a/tests/mysql/macros.rs b/tests/mysql/macros.rs
index 9b9b436c..80eb1b2e 100644
--- a/tests/mysql/macros.rs
+++ b/tests/mysql/macros.rs
@@ -188,12 +188,13 @@ async fn test_column_override_nullable() -> anyhow::Result<()> {
 
 async fn with_test_row<'a>(
     conn: &'a mut MySqlConnection,
-) -> anyhow::Result<Transaction<'a, MySql>> {
+) -> anyhow::Result<(Transaction<'a, MySql>, MyInt)> {
     let mut transaction = conn.begin().await?;
-    sqlx::query!("INSERT INTO tweet(id, text, owner_id) VALUES (1, '#sqlx is pretty cool!', 1)")
+    let id = sqlx::query!("INSERT INTO tweet(text, owner_id) VALUES ('#sqlx is pretty cool!', 1)")
         .execute(&mut transaction)
-        .await?;
-    Ok(transaction)
+        .await?
+        .last_insert_id();
+    Ok((transaction, MyInt(id as i64)))
 }
 
 #[derive(PartialEq, Eq, Debug, sqlx::Type)]
@@ -211,13 +212,13 @@ struct OptionalRecord {
 #[sqlx_macros::test]
 async fn test_column_override_wildcard() -> anyhow::Result<()> {
     let mut conn = new::<MySql>().await?;
-    let mut conn = with_test_row(&mut conn).await?;
+    let (mut conn, id) = with_test_row(&mut conn).await?;
 
     let record = sqlx::query_as!(Record, "select id as `id: _` from tweet")
         .fetch_one(&mut conn)
         .await?;
 
-    assert_eq!(record.id, MyInt(1));
+    assert_eq!(record.id, id);
 
     // this syntax is also useful for expressions
     let record = sqlx::query_as!(Record, "select * from (select 1 as `id: _`) records")
@@ -238,7 +239,7 @@ async fn test_column_override_wildcard() -> anyhow::Result<()> {
 #[sqlx_macros::test]
 async fn test_column_override_wildcard_not_null() -> anyhow::Result<()> {
     let mut conn = new::<MySql>().await?;
-    let mut conn = with_test_row(&mut conn).await?;
+    let (mut conn, _) = with_test_row(&mut conn).await?;
 
     let record = sqlx::query_as!(Record, "select owner_id as `id!: _` from tweet")
         .fetch_one(&mut conn)
@@ -252,13 +253,13 @@ async fn test_column_override_wildcard_not_null() -> anyhow::Result<()> {
 #[sqlx_macros::test]
 async fn test_column_override_wildcard_nullable() -> anyhow::Result<()> {
     let mut conn = new::<MySql>().await?;
-    let mut conn = with_test_row(&mut conn).await?;
+    let (mut conn, id) = with_test_row(&mut conn).await?;
 
     let record = sqlx::query_as!(OptionalRecord, "select id as `id?: _` from tweet")
         .fetch_one(&mut conn)
         .await?;
 
-    assert_eq!(record.id, Some(MyInt(1)));
+    assert_eq!(record.id, Some(id));
 
     Ok(())
 }
@@ -266,13 +267,13 @@ async fn test_column_override_wildcard_nullable() -> anyhow::Result<()> {
 #[sqlx_macros::test]
 async fn test_column_override_exact() -> anyhow::Result<()> {
     let mut conn = new::<MySql>().await?;
-    let mut conn = with_test_row(&mut conn).await?;
+    let (mut conn, id) = with_test_row(&mut conn).await?;
 
     let record = sqlx::query!("select id as `id: MyInt` from tweet")
         .fetch_one(&mut conn)
         .await?;
 
-    assert_eq!(record.id, MyInt(1));
+    assert_eq!(record.id, id);
 
     // we can also support this syntax for expressions
     let record = sqlx::query!("select * from (select 1 as `id: MyInt`) records")
@@ -293,7 +294,7 @@ async fn test_column_override_exact() -> anyhow::Result<()> {
 #[sqlx_macros::test]
 async fn test_column_override_exact_not_null() -> anyhow::Result<()> {
     let mut conn = new::<MySql>().await?;
-    let mut conn = with_test_row(&mut conn).await?;
+    let (mut conn, _) = with_test_row(&mut conn).await?;
 
     let record = sqlx::query!("select owner_id as `id!: MyInt` from tweet")
         .fetch_one(&mut conn)
@@ -307,13 +308,13 @@ async fn test_column_override_exact_not_null() -> anyhow::Result<()> {
 #[sqlx_macros::test]
 async fn test_column_override_exact_nullable() -> anyhow::Result<()> {
     let mut conn = new::<MySql>().await?;
-    let mut conn = with_test_row(&mut conn).await?;
+    let (mut conn, id) = with_test_row(&mut conn).await?;
 
     let record = sqlx::query!("select id as `id?: MyInt` from tweet")
         .fetch_one(&mut conn)
         .await?;
 
-    assert_eq!(record.id, Some(MyInt(1)));
+    assert_eq!(record.id, Some(id));
 
     Ok(())
 }
diff --git a/tests/postgres/postgres.rs b/tests/postgres/postgres.rs
index 5688aded..4f71cde7 100644
--- a/tests/postgres/postgres.rs
+++ b/tests/postgres/postgres.rs
@@ -2,7 +2,7 @@ use futures::TryStreamExt;
 use sqlx::postgres::{
     PgConnectOptions, PgConnection, PgDatabaseError, PgErrorPosition, PgSeverity,
 };
-use sqlx::postgres::{PgPoolOptions, PgRow, Postgres};
+use sqlx::postgres::{PgConnectionInfo, PgPoolOptions, PgRow, Postgres};
 use sqlx::{Column, Connection, Executor, Row, Statement, TypeInfo};
 use sqlx_test::{new, setup_if_needed};
 use std::env;
@@ -968,6 +968,30 @@ async fn test_listener_cleanup() -> anyhow::Result<()> {
 
 #[sqlx_macros::test]
 async fn it_supports_domain_types_in_composite_domain_types() -> anyhow::Result<()> {
+    // Only supported in Postgres 11+
+    let mut conn = new::<Postgres>().await?;
+    if matches!(conn.server_version_num(), Some(version) if version < 110000) {
+        return Ok(());
+    }
+
+    conn.execute(
+        r#"
+DROP TABLE IF EXISTS heating_bills;
+DROP DOMAIN IF EXISTS winter_year_month;
+DROP TYPE IF EXISTS year_month;
+DROP DOMAIN IF EXISTS month_id;
+
+CREATE DOMAIN month_id AS INT2 CHECK (1 <= value AND value <= 12);
+CREATE TYPE year_month AS (year INT4, month month_id);
+CREATE DOMAIN winter_year_month AS year_month CHECK ((value).month <= 3);
+CREATE TABLE heating_bills (
+  month winter_year_month NOT NULL PRIMARY KEY,
+  cost INT4 NOT NULL
+);
+    "#,
+    )
+    .await?;
+
     #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
     struct MonthId(i16);
 
@@ -1039,41 +1063,44 @@ async fn it_supports_domain_types_in_composite_domain_types() -> anyhow::Result<
             sqlx::encode::IsNull::No
         }
     }
-
     let mut conn = new::<Postgres>().await?;
 
-    {
-        let result = sqlx::query("DELETE FROM heating_bills;")
-            .execute(&mut conn)
-            .await;
-
-        let result = result.unwrap();
-        assert_eq!(result.rows_affected(), 1);
-    }
-
-    {
-        let result = sqlx::query(
-            "INSERT INTO heating_bills(month, cost) VALUES($1::winter_year_month, 100);",
-        )
-        .bind(WinterYearMonth {
-            year: 2021,
-            month: MonthId(1),
-        })
+    let result = sqlx::query("DELETE FROM heating_bills;")
         .execute(&mut conn)
         .await;
 
-        let result = result.unwrap();
-        assert_eq!(result.rows_affected(), 1);
-    }
+    let result = result.unwrap();
+    assert_eq!(result.rows_affected(), 0);
 
-    {
-        let result = sqlx::query("DELETE FROM heating_bills;")
+    let result =
+        sqlx::query("INSERT INTO heating_bills(month, cost) VALUES($1::winter_year_month, 100);")
+            .bind(WinterYearMonth {
+                year: 2021,
+                month: MonthId(1),
+            })
             .execute(&mut conn)
             .await;
 
-        let result = result.unwrap();
-        assert_eq!(result.rows_affected(), 1);
-    }
+    let result = result.unwrap();
+    assert_eq!(result.rows_affected(), 1);
+
+    let result = sqlx::query("DELETE FROM heating_bills;")
+        .execute(&mut conn)
+        .await;
+
+    let result = result.unwrap();
+    assert_eq!(result.rows_affected(), 1);
+
+    Ok(())
+}
+
+#[sqlx_macros::test]
+async fn test_pg_server_num() -> anyhow::Result<()> {
+    use sqlx::postgres::PgConnectionInfo;
+
+    let conn = new::<Postgres>().await?;
+
+    assert!(conn.server_version_num().is_some());
 
     Ok(())
 }
diff --git a/tests/postgres/setup.sql b/tests/postgres/setup.sql
index d013d434..9818d139 100644
--- a/tests/postgres/setup.sql
+++ b/tests/postgres/setup.sql
@@ -29,11 +29,3 @@ CREATE TABLE products (
     name TEXT,
     price NUMERIC CHECK (price > 0)
 );
-
-CREATE DOMAIN month_id AS INT2 CHECK (1 <= value AND value <= 12);
-CREATE TYPE year_month AS (year INT4, month month_id);
-CREATE DOMAIN winter_year_month AS year_month CHECK ((value).month <= 3);
-CREATE TABLE heating_bills (
-  month winter_year_month NOT NULL PRIMARY KEY,
-  cost INT4 NOT NULL
-);
diff --git a/tests/postgres/types.rs b/tests/postgres/types.rs
index 5ae5bd21..932f6b81 100644
--- a/tests/postgres/types.rs
+++ b/tests/postgres/types.rs
@@ -211,7 +211,7 @@ test_type!(ipnetwork_vec<Vec<sqlx::types::ipnetwork::IpNetwork>>(Postgres,
 
 #[cfg(feature = "mac_address")]
 test_type!(mac_address_vec<Vec<sqlx::types::mac_address::MacAddress>>(Postgres,
-    "'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::inet[]"
+    "'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::macaddr[]"
         == vec![
            "01:02:03:04:05:06".parse::<sqlx::types::mac_address::MacAddress>().unwrap(),
            "FF:FF:FF:FF:FF:FF".parse::<sqlx::types::mac_address::MacAddress>().unwrap()
diff --git a/tests/sqlite/sqlite.db b/tests/sqlite/sqlite.db
index 49913441..d6935110 100644
Binary files a/tests/sqlite/sqlite.db and b/tests/sqlite/sqlite.db differ
diff --git a/tests/x.py b/tests/x.py
index 2133beef..ed1c7f51 100755
--- a/tests/x.py
+++ b/tests/x.py
@@ -88,116 +88,101 @@ for path in glob(os.path.join(os.path.dirname(__file__), "target/**/*.gc*"), rec
 # check
 #
 
-run("cargo c", comment="check with a default set of features", tag="check")
-
-run(
-    "cargo c --no-default-features --features runtime-async-std-native-tls,all-databases,all-types,offline,macros",
-    comment="check with async-std",
-    tag="check_async_std"
-)
-
-run(
-    "cargo c --no-default-features --features runtime-tokio-native-tls,all-databases,all-types,offline,macros",
-    comment="check with tokio",
-    tag="check_tokio"
-)
-
-run(
-    "cargo c --no-default-features --features runtime-actix-native-tls,all-databases,all-types,offline,macros",
-    comment="check with actix",
-    tag="check_actix"
-)
+for runtime in ["async-std", "tokio", "actix"]:
+    for tls in ["native-tls", "rustls"]:
+        run(
+            f"cargo c --no-default-features --features all-databases,all-types,offline,macros,runtime-{runtime}-{tls}",
+            comment="check with async-std",
+            tag=f"check_{runtime}_{tls}"
+        )
 
 #
 # unit test
 #
 
-run(
-    "cargo test --manifest-path sqlx-core/Cargo.toml --features all-databases,all-types",
-    comment="unit test core",
-    tag="unit"
-)
-
-run(
-    "cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features all-databases,all-types,runtime-tokio-native-tls",
-    comment="unit test core",
-    tag="unit_tokio"
-)
+for runtime in ["async-std", "tokio", "actix"]:
+    for tls in ["native-tls", "rustls"]:
+        run(
+            f"cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features all-databases,all-types,runtime-{runtime}-{tls}",
+            comment="unit test core",
+            tag=f"unit_{runtime}_{tls}"
+        )
 
 #
 # integration tests
 #
 
 for runtime in ["async-std", "tokio", "actix"]:
+    for tls in ["native-tls", "rustls"]:
 
-    #
-    # sqlite
-    #
+        #
+        # sqlite
+        #
 
-    run(
-        f"cargo test --no-default-features --features macros,offline,any,all-types,sqlite,runtime-{runtime}-native-tls",
-        comment=f"test sqlite",
-        service="sqlite",
-        tag=f"sqlite" if runtime == "async-std" else f"sqlite_{runtime}",
-    )
-
-    #
-    # postgres
-    #
-
-    for version in ["12", "10", "9_6", "9_5"]:
         run(
-            f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-native-tls",
-            comment=f"test postgres {version}",
-            service=f"postgres_{version}",
-            tag=f"postgres_{version}" if runtime == "async-std" else f"postgres_{version}_{runtime}",
+            f"cargo test --no-default-features --features macros,offline,any,all-types,sqlite,runtime-{runtime}-native-tls",
+            comment=f"test sqlite",
+            service="sqlite",
+            tag=f"sqlite" if runtime == "async-std" else f"sqlite_{runtime}",
         )
 
-    # +ssl
-    for version in ["12", "10", "9_6", "9_5"]:
-        run(
-            f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-native-tls",
-            comment=f"test postgres {version} ssl",
-            database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt",
-            service=f"postgres_{version}",
-            tag=f"postgres_{version}_ssl" if runtime == "async-std" else f"postgres_{version}_ssl_{runtime}",
-        )
+        #
+        # postgres
+        #
 
-    #
-    # mysql
-    #
+        for version in ["13", "12", "11", "10", "9_6"]:
+            run(
+                f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-native-tls",
+                comment=f"test postgres {version}",
+                service=f"postgres_{version}",
+                tag=f"postgres_{version}" if runtime == "async-std" else f"postgres_{version}_{runtime}",
+            )
 
-    for version in ["8", "5_7", "5_6"]:
-        run(
-            f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-native-tls",
-            comment=f"test mysql {version}",
-            service=f"mysql_{version}",
-            tag=f"mysql_{version}" if runtime == "async-std" else f"mysql_{version}_{runtime}",
-        )
+        ## +ssl
+        for version in ["13", "12", "11", "10", "9_6"]:
+            run(
+                f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-native-tls",
+                comment=f"test postgres {version} ssl",
+                database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt",
+                service=f"postgres_{version}",
+                tag=f"postgres_{version}_ssl" if runtime == "async-std" else f"postgres_{version}_ssl_{runtime}",
+            )
 
-    #
-    # mariadb
-    #
+        #
+        # mysql
+        #
 
-    for version in ["10_5", "10_4", "10_3", "10_2", "10_1"]:
-        run(
-            f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-native-tls",
-            comment=f"test mariadb {version}",
-            service=f"mariadb_{version}",
-            tag=f"mariadb_{version}" if runtime == "async-std" else f"mariadb_{version}_{runtime}",
-        )
+        for version in ["8", "5_7", "5_6"]:
+            run(
+                f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-native-tls",
+                comment=f"test mysql {version}",
+                service=f"mysql_{version}",
+                tag=f"mysql_{version}" if runtime == "async-std" else f"mysql_{version}_{runtime}",
+            )
 
-    #
-    # mssql
-    #
+        #
+        # mariadb
+        #
 
-    for version in ["2019"]:
-        run(
-            f"cargo test --no-default-features --features macros,offline,any,all-types,mssql,runtime-{runtime}-native-tls",
-            comment=f"test mssql {version}",
-            service=f"mssql_{version}",
-            tag=f"mssql_{version}" if runtime == "async-std" else f"mssql_{version}_{runtime}",
-        )
+        for version in ["10_6", "10_5", "10_4", "10_3", "10_2"]:
+            run(
+                f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-native-tls",
+                comment=f"test mariadb {version}",
+                service=f"mariadb_{version}",
+                tag=f"mariadb_{version}" if runtime == "async-std" else f"mariadb_{version}_{runtime}",
+            )
+
+        #
+        # mssql
+        #
+
+        for version in ["2019", "2017"]:
+            run(
+                f"cargo test --no-default-features --features macros,offline,any,all-types,mssql,runtime-{runtime}-native-tls",
+                comment=f"test mssql {version}",
+                service=f"mssql_{version}",
+                tag=f"mssql_{version}" if runtime == "async-std" else f"mssql_{version}_{runtime}",
+            )
 
 # TODO: Use [grcov] if available
 # ~/.cargo/bin/grcov tests/.cache/target/debug -s sqlx-core/ -t html --llvm --branch -o ./target/debug/coverage