diff --git a/Cargo.lock b/Cargo.lock
index ec27bcbca..3f2928c6d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3254,6 +3254,7 @@ dependencies = [
  "kanidm_proto",
  "kanidmd_core",
  "kanidmd_lib",
+ "ldap3_client",
  "oauth2 4.4.2",
  "openssl",
  "petgraph",
diff --git a/server/core/src/ldaps.rs b/server/core/src/ldaps.rs
index f8e76678f..ca57a7e1b 100644
--- a/server/core/src/ldaps.rs
+++ b/server/core/src/ldaps.rs
@@ -1,8 +1,5 @@
-use std::net;
-use std::pin::Pin;
-use std::str::FromStr;
-
 use crate::actors::QueryServerReadV1;
+use crate::CoreAction;
 use futures_util::sink::SinkExt;
 use futures_util::stream::StreamExt;
 use kanidmd_lib::idm::ldap::{LdapBoundToken, LdapResponseState};
@@ -10,13 +7,15 @@ use kanidmd_lib::prelude::*;
 use ldap3_proto::proto::LdapMsg;
 use ldap3_proto::LdapCodec;
 use openssl::ssl::{Ssl, SslAcceptor};
+use std::net;
+use std::pin::Pin;
+use std::str::FromStr;
+use tokio::io::{AsyncRead, AsyncWrite};
 use tokio::net::{TcpListener, TcpStream};
-use tokio_openssl::SslStream;
-use tokio_util::codec::{FramedRead, FramedWrite};
-
-use crate::CoreAction;
 use tokio::sync::broadcast;
 use tokio::sync::mpsc;
+use tokio_openssl::SslStream;
+use tokio_util::codec::{FramedRead, FramedWrite};
 
 struct LdapSession {
     uat: Option<LdapBoundToken>,
@@ -49,28 +48,14 @@ async fn client_process_msg(
         .await
 }
 
-async fn client_process(
-    tcpstream: TcpStream,
-    tls_acceptor: SslAcceptor,
+async fn client_process<STREAM>(
+    stream: STREAM,
     client_address: net::SocketAddr,
     qe_r_ref: &'static QueryServerReadV1,
-) {
-    // Start the event
-    // From the parameters we need to create an SslContext.
-    let mut tlsstream = match Ssl::new(tls_acceptor.context())
-        .and_then(|tls_obj| SslStream::new(tls_obj, tcpstream))
-    {
-        Ok(ta) => ta,
-        Err(e) => {
-            error!("LDAP TLS setup error, continuing -> {:?}", e);
-            return;
-        }
-    };
-    if let Err(e) = SslStream::accept(Pin::new(&mut tlsstream)).await {
-        error!("LDAP TLS accept error, continuing -> {:?}", e);
-        return;
-    };
-    let (r, w) = tokio::io::split(tlsstream);
+) where
+    STREAM: AsyncRead + AsyncWrite,
+{
+    let (r, w) = tokio::io::split(stream);
     let mut r = FramedRead::new(r, LdapCodec::default());
     let mut w = FramedWrite::new(w, LdapCodec::default());
 
@@ -126,7 +111,32 @@ async fn client_process(
     }
 }
 
-/// TLS LDAP Listener, hands off to [client_process]
+async fn client_tls_accept(
+    tcpstream: TcpStream,
+    tls_acceptor: SslAcceptor,
+    client_socket_addr: net::SocketAddr,
+    qe_r_ref: &'static QueryServerReadV1,
+) {
+    // Start the event
+    // From the parameters we need to create an SslContext.
+    let mut tlsstream = match Ssl::new(tls_acceptor.context())
+        .and_then(|tls_obj| SslStream::new(tls_obj, tcpstream))
+    {
+        Ok(ta) => ta,
+        Err(err) => {
+            error!(?err, %client_socket_addr, "LDAP TLS setup error");
+            return;
+        }
+    };
+    if let Err(err) = SslStream::accept(Pin::new(&mut tlsstream)).await {
+        error!(?err, %client_socket_addr, "LDAP TLS accept error");
+        return;
+    };
+
+    tokio::spawn(client_process(tlsstream, client_socket_addr, qe_r_ref));
+}
+
+/// TLS LDAP Listener, hands off to [client_tls_accept]
 async fn ldap_tls_acceptor(
     listener: TcpListener,
     mut tls_acceptor: SslAcceptor,
@@ -145,10 +155,10 @@ async fn ldap_tls_acceptor(
                 match accept_result {
                     Ok((tcpstream, client_socket_addr)) => {
                         let clone_tls_acceptor = tls_acceptor.clone();
-                        tokio::spawn(client_process(tcpstream, clone_tls_acceptor, client_socket_addr, qe_r_ref));
+                        tokio::spawn(client_tls_accept(tcpstream, clone_tls_acceptor, client_socket_addr, qe_r_ref));
                     }
-                    Err(e) => {
-                        error!("LDAP acceptor error, continuing -> {:?}", e);
+                    Err(err) => {
+                        warn!(?err, "LDAP acceptor error, continuing");
                     }
                 }
             }
@@ -161,6 +171,34 @@ async fn ldap_tls_acceptor(
     info!("Stopped {}", super::TaskName::LdapActor);
 }
 
+/// PLAIN LDAP Listener, hands off to [client_process]
+async fn ldap_plaintext_acceptor(
+    listener: TcpListener,
+    qe_r_ref: &'static QueryServerReadV1,
+    mut rx: broadcast::Receiver<CoreAction>,
+) {
+    loop {
+        tokio::select! {
+            Ok(action) = rx.recv() => {
+                match action {
+                    CoreAction::Shutdown => break,
+                }
+            }
+            accept_result = listener.accept() => {
+                match accept_result {
+                    Ok((tcpstream, client_socket_addr)) => {
+                        tokio::spawn(client_process(tcpstream, client_socket_addr, qe_r_ref));
+                    }
+                    Err(e) => {
+                        error!("LDAP acceptor error, continuing -> {:?}", e);
+                    }
+                }
+            }
+        }
+    }
+    info!("Stopped {}", super::TaskName::LdapActor);
+}
+
 pub(crate) async fn create_ldap_server(
     address: &str,
     opt_ssl_acceptor: Option<SslAcceptor>,
@@ -197,10 +235,7 @@ pub(crate) async fn create_ldap_server(
                 tls_acceptor_reload_rx,
             ))
         }
-        None => {
-            error!("The server won't run without TLS!");
-            return Err(());
-        }
+        None => tokio::spawn(ldap_plaintext_acceptor(listener, qe_r_ref, rx)),
     };
 
     info!("Created LDAP interface");
diff --git a/server/core/src/lib.rs b/server/core/src/lib.rs
index b956735cd..f781998dc 100644
--- a/server/core/src/lib.rs
+++ b/server/core/src/lib.rs
@@ -1080,20 +1080,15 @@ pub async fn create_server_core(
         Some(la) => {
             let opt_ldap_ssl_acceptor = maybe_tls_acceptor.clone();
 
-            if !config_test {
-                // ⚠️  only start the sockets and listeners in non-config-test modes.
-                let h = ldaps::create_ldap_server(
-                    la.as_str(),
-                    opt_ldap_ssl_acceptor,
-                    server_read_ref,
-                    broadcast_tx.subscribe(),
-                    ldap_tls_acceptor_reload_rx,
-                )
-                .await?;
-                Some(h)
-            } else {
-                None
-            }
+            let h = ldaps::create_ldap_server(
+                la.as_str(),
+                opt_ldap_ssl_acceptor,
+                server_read_ref,
+                broadcast_tx.subscribe(),
+                ldap_tls_acceptor_reload_rx,
+            )
+            .await?;
+            Some(h)
         }
         None => {
             debug!("LDAP not requested, skipping");
diff --git a/server/lib-macros/src/entry.rs b/server/lib-macros/src/entry.rs
index aad516042..217751156 100644
--- a/server/lib-macros/src/entry.rs
+++ b/server/lib-macros/src/entry.rs
@@ -34,7 +34,7 @@ fn parse_attributes(
     });
 
     if !args_are_allowed {
-        let msg = "Invalid test config attribute. The following are allow";
+        let msg = "Invalid test config attribute. The following are allowed";
         return Err(syn::Error::new_spanned(
             input.sig.fn_token,
             format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),
diff --git a/server/lib/src/be/idl_sqlite.rs b/server/lib/src/be/idl_sqlite.rs
index a1c5ab377..09531c90a 100644
--- a/server/lib/src/be/idl_sqlite.rs
+++ b/server/lib/src/be/idl_sqlite.rs
@@ -205,7 +205,7 @@ pub(crate) trait IdlSqliteTransaction {
         let mut stmt = self
             .get_conn()?
             .prepare(&format!(
-                "SELECT rowid from {}.sqlite_master where name = :tname LIMIT 1",
+                "SELECT rowid from {}.sqlite_master where type=\"table\" AND name = :tname LIMIT 1",
                 self.get_db_name()
             ))
             .map_err(sqlite_error)?;
diff --git a/server/testkit-macros/src/entry.rs b/server/testkit-macros/src/entry.rs
index d6a3561da..0566973e4 100644
--- a/server/testkit-macros/src/entry.rs
+++ b/server/testkit-macros/src/entry.rs
@@ -14,87 +14,73 @@ const ALLOWED_ATTRIBUTES: &[&str] = &[
     "role",
     "output_mode",
     "log_level",
+    "ldap",
 ];
 
-fn parse_knobs(
-    input: &syn::ItemFn,
-    server_config: &Punctuated<ExprAssign, syn::token::Comma>,
-) -> TokenStream {
-    // If type mismatch occurs, the current rustc points to the last statement.
-    let (last_stmt_start_span, _last_stmt_end_span) = {
-        let mut last_stmt = input
-            .block
-            .stmts
-            .last()
-            .map(ToTokens::into_token_stream)
-            .unwrap_or_default()
-            .into_iter();
-        // `Span` on stable Rust has a limitation that only points to the first
-        // token, not the whole tokens. We can work around this limitation by
-        // using the first/last span of the tokens like
-        // `syn::Error::new_spanned` does.
-        let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
-        let end = last_stmt.last().map_or(start, |t| t.span());
-        (start, end)
-    };
+#[derive(Default)]
+struct Flags {
+    ldap: bool,
+}
 
-    // here we gather all the provided configuration in a struct like declaration
-    // By now we have already checked that the configurations provided belong to the allowed subset
-    let mut field_modifications = quote! {};
-    server_config.pairs().for_each(|p| {
-        let field_name = p.value().left.to_token_stream(); // here we can use to_token_stream as we know we're iterating over ExprAssigns
-        let field_value = p.value().right.to_token_stream();
-        field_modifications.extend(quote! {
-        #field_name: #field_value,})
+fn parse_attributes(
+    args: &TokenStream,
+    input: &syn::ItemFn,
+) -> Result<(proc_macro2::TokenStream, Flags), syn::Error> {
+    let args: Punctuated<ExprAssign, syn::token::Comma> =
+        Punctuated::<ExprAssign, Token![,]>::parse_terminated.parse(args.clone())?;
+
+    let args_are_allowed = args.pairs().all(|p| {
+        ALLOWED_ATTRIBUTES.to_vec().contains(
+            &p.value()
+                .left
+                .span()
+                .source_text()
+                .unwrap_or_default()
+                .as_str(),
+        )
     });
 
-    // Setup the config filling the remaining fields with the default values
-    let default_config_struct = quote!(kanidmd_core::config::Configuration {
+    if !args_are_allowed {
+        let msg = "Invalid test config attribute. The following are allowed";
+        return Err(syn::Error::new_spanned(
+            input.sig.fn_token,
+            format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),
+        ));
+    }
+
+    let mut flags = Flags::default();
+    let mut field_modifications = quote! {};
+
+    args.pairs().for_each(|p| {
+        match p
+            .value()
+            .left
+            .span()
+            .source_text()
+            .unwrap_or_default()
+            .as_str()
+        {
+            "ldap" => {
+                flags.ldap = true;
+                field_modifications.extend(quote! {
+                ldapaddress: Some("on".to_string()),})
+            }
+            _ => {
+                let field_name = p.value().left.to_token_stream(); // here we can use to_token_stream as we know we're iterating over ExprAssigns
+                let field_value = p.value().right.to_token_stream();
+                // This is printing out struct members.
+                field_modifications.extend(quote! {
+                #field_name: #field_value,})
+            }
+        }
+    });
+
+    let ts = quote!(kanidmd_core::config::Configuration {
         #field_modifications
         ..kanidmd_core::config::Configuration::new_for_test()
     });
 
-    let rt = quote_spanned! {last_stmt_start_span=>
-        tokio::runtime::Builder::new_current_thread()
-    };
-
-    let header = quote! {
-        #[::core::prelude::v1::test]
-    };
-
-    let fn_name = &input.sig.ident;
-    let test_driver = Ident::new(&format!("tk_{}", fn_name), input.sig.span());
-
-    // Effectively we are just injecting a real test function around this which we will
-    // call.
-
-    let result = quote! {
-        #input
-
-        #header
-        fn #test_driver() {
-            let body = async {
-                let (rsclient, mut core_handle) = kanidmd_testkit::setup_async_test(#default_config_struct).await;
-                #fn_name(rsclient).await;
-                core_handle.shutdown().await;
-            };
-            #[allow(clippy::expect_used, clippy::diverging_sub_expression)]
-            {
-                return #rt
-                    .enable_all()
-                    .build()
-                    .expect("Failed building the Runtime")
-                    .block_on(body);
-            }
-        }
-    };
-
-    result.into()
-}
-
-fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
-    tokens.extend(TokenStream::from(error.into_compile_error()));
-    tokens
+    Ok((ts, flags))
 }
 
 pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
@@ -115,31 +101,80 @@ pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
         let msg = "the `async` keyword is missing from the function declaration";
         return token_stream_with_error(item, syn::Error::new_spanned(input.sig.fn_token, msg));
     }
-    let args: Punctuated<ExprAssign, syn::token::Comma> =
-        match Punctuated::<ExprAssign, Token![,]>::parse_terminated.parse(args.clone()) {
-            Ok(it) => it,
-            Err(e) => return token_stream_with_error(args, e),
-        };
-    let args_are_allowed = args.pairs().all(|p| {
-        ALLOWED_ATTRIBUTES.to_vec().contains(
-            &p.value()
-                .left
-                .span()
-                .source_text()
-                .unwrap_or_default()
-                .as_str(),
-        )
-    });
-    if !args_are_allowed {
-        let msg =
-            "Currently only a subset of all the server configs can be set. Here is the full list";
-        return token_stream_with_error(
-            item,
-            syn::Error::new_spanned(
-                input.sig.fn_token,
-                format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),
-            ),
-        );
-    }
-    parse_knobs(&input, &args)
+
+    // If type mismatch occurs, the current rustc points to the last statement.
+    let (last_stmt_start_span, _last_stmt_end_span) = {
+        let mut last_stmt = input
+            .block
+            .stmts
+            .last()
+            .map(ToTokens::into_token_stream)
+            .unwrap_or_default()
+            .into_iter();
+        // `Span` on stable Rust has a limitation that only points to the first
+        // token, not the whole tokens. We can work around this limitation by
+        // using the first/last span of the tokens like
+        // `syn::Error::new_spanned` does.
+        let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
+        let end = last_stmt.last().map_or(start, |t| t.span());
+        (start, end)
+    };
+
+    // Setup the config filling the remaining fields with the default values
+    let (default_config_struct, flags) = match parse_attributes(&args, &input) {
+        Ok(dc) => dc,
+        Err(e) => return token_stream_with_error(args, e),
+    };
+
+    let rt = quote_spanned! {last_stmt_start_span=>
+        tokio::runtime::Builder::new_current_thread()
+    };
+
+    let header = quote! {
+        #[::core::prelude::v1::test]
+    };
+
+    let test_fn_args = if flags.ldap {
+        quote! {
+            &test_env
+        }
+    } else {
+        quote! {
+            &test_env.rsclient
+        }
+    };
+
+    let test_fn = &input.sig.ident;
+    let test_driver = Ident::new(&format!("tk_{}", test_fn), input.sig.span());
+
+    // Effectively we are just injecting a real test function around this which we will
+    // call.
+    let result = quote! {
+        #input
+
+        #header
+        fn #test_driver() {
+            let body = async {
+                let mut test_env = kanidmd_testkit::setup_async_test(#default_config_struct).await;
+
+                #test_fn(#test_fn_args).await;
+                test_env.core_handle.shutdown().await;
+            };
+            #[allow(clippy::expect_used, clippy::diverging_sub_expression)]
+            {
+                return #rt
+                    .enable_all()
+                    .build()
+                    .expect("Failed building the Runtime")
+                    .block_on(body);
+            }
+        }
+    };
+
+    result.into()
+}
+
+fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
+    tokens.extend(TokenStream::from(error.into_compile_error()));
+    tokens
 }
diff --git a/server/testkit/Cargo.toml b/server/testkit/Cargo.toml
index 21f0498f1..823458b14 100644
--- a/server/testkit/Cargo.toml
+++ b/server/testkit/Cargo.toml
@@ -53,6 +53,7 @@ escargot = "0.5.13"
 # used for webdriver testing
 fantoccini = { version = "0.21.4" }
 futures = { workspace = true }
+ldap3_client = { workspace = true }
 oauth2_ext = { workspace = true, default-features = false, features = [
     "reqwest",
 ] }
diff --git a/server/testkit/src/lib.rs b/server/testkit/src/lib.rs
index 6dd4677dd..9b1edd3d8 100644
--- a/server/testkit/src/lib.rs
+++ b/server/testkit/src/lib.rs
@@ -10,16 +10,16 @@
 #![deny(clippy::needless_pass_by_value)]
 #![deny(clippy::trivially_copy_pass_by_ref)]
 
-use std::net::TcpStream;
-use std::sync::atomic::{AtomicU16, Ordering};
-
 use kanidm_client::{KanidmClient, KanidmClientBuilder};
-
 use kanidm_proto::internal::{Filter, Modify, ModifyList};
 use kanidmd_core::config::{Configuration, IntegrationTestConfig};
 use kanidmd_core::{create_server_core, CoreHandle};
 use kanidmd_lib::prelude::{Attribute, NAME_SYSTEM_ADMINS};
+use std::net::TcpStream;
+use std::sync::atomic::{AtomicU16, Ordering};
 use tokio::task;
+use tracing::error;
+use url::Url;
 
 pub const ADMIN_TEST_USER: &str = "admin";
 pub const ADMIN_TEST_PASSWORD: &str = "integration test admin password";
@@ -46,14 +46,9 @@ pub fn is_free_port(port: u16) -> bool {
 }
 
 // Test external behaviours of the service.
-
-// allowed because the use of this function is behind a test gate
-#[allow(dead_code)]
-pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreHandle) {
-    sketching::test_init();
-
+fn port_loop() -> u16 {
     let mut counter = 0;
-    let port = loop {
+    loop {
         let possible_port = PORT_ALLOC.fetch_add(1, Ordering::SeqCst);
         if is_free_port(possible_port) {
             break possible_port;
@@ -64,7 +59,21 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH
             tracing::error!("Unable to allocate port!");
             panic!();
         }
-    };
+    }
+}
+
+pub struct AsyncTestEnvironment {
+    pub rsclient: KanidmClient,
+    pub core_handle: CoreHandle,
+    pub ldap_url: Option<Url>,
+}
+
+// allowed because the use of this function is behind a test gate
+#[allow(dead_code)]
+pub async fn setup_async_test(mut config: Configuration) -> AsyncTestEnvironment {
+    sketching::test_init();
+
+    let port = port_loop();
 
     let int_config = Box::new(IntegrationTestConfig {
         admin_user: ADMIN_TEST_USER.to_string(),
@@ -75,6 +84,16 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH
 
     let addr = format!("http://localhost:{}", port);
 
+    let ldap_url = if config.ldapaddress.is_some() {
+        let ldapport = port_loop();
+        config.ldapaddress = Some(format!("127.0.0.1:{}", ldapport));
+        Url::parse(&format!("ldap://127.0.0.1:{}", ldapport))
+            .inspect_err(|err| error!(?err, "ldap address setup"))
+            .ok()
+    } else {
+        None
+    };
+
     // Setup the address and origin..
     config.address = format!("127.0.0.1:{}", port);
     config.integration_test_config = Some(int_config);
@@ -102,7 +121,11 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH
 
     tracing::info!("Testkit server setup complete - {}", addr);
 
-    (rsclient, core_handle)
+    AsyncTestEnvironment {
+        rsclient,
+        core_handle,
+        ldap_url,
+    }
 }
 
 /// creates a user (username: `id`) and puts them into a group, creating it if need be.
diff --git a/server/testkit/tests/testkit/apidocs.rs b/server/testkit/tests/testkit/apidocs.rs
index 1f1ef5d84..b059ba336 100644
--- a/server/testkit/tests/testkit/apidocs.rs
+++ b/server/testkit/tests/testkit/apidocs.rs
@@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
 use tracing::info;
 
 #[kanidmd_testkit::test]
-async fn check_that_the_swagger_api_loads(rsclient: kanidm_client::KanidmClient) {
+async fn check_that_the_swagger_api_loads(rsclient: &kanidm_client::KanidmClient) {
     #[derive(Serialize, Deserialize, Debug)]
     struct OpenAPIResponse {
         pub openapi: String,
diff --git a/server/testkit/tests/testkit/domain.rs b/server/testkit/tests/testkit/domain.rs
index 37dfe9f10..f88e78ea5 100644
--- a/server/testkit/tests/testkit/domain.rs
+++ b/server/testkit/tests/testkit/domain.rs
@@ -3,7 +3,7 @@ use kanidm_proto::constants::ATTR_DOMAIN_DISPLAY_NAME;
 use kanidmd_testkit::{ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
 
 #[kanidmd_testkit::test]
-async fn test_idm_set_ldap_allow_unix_password_bind(rsclient: KanidmClient) {
+async fn test_idm_set_ldap_allow_unix_password_bind(rsclient: &KanidmClient) {
     rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await
@@ -13,8 +13,9 @@ async fn test_idm_set_ldap_allow_unix_password_bind(rsclient: KanidmClient) {
         .await
         .expect("Failed to set LDAP allow unix password bind to true");
 }
+
 #[kanidmd_testkit::test]
-async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
+async fn test_idm_domain_set_ldap_basedn(rsclient: &KanidmClient) {
     rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await
@@ -27,7 +28,7 @@ async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
+async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: &KanidmClient) {
     rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await
@@ -40,7 +41,7 @@ async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_idm_domain_set_display_name(rsclient: KanidmClient) {
+async fn test_idm_domain_set_display_name(rsclient: &KanidmClient) {
     rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await
diff --git a/server/testkit/tests/testkit/group.rs b/server/testkit/tests/testkit/group.rs
index 67bf05e28..4eaeb30a0 100644
--- a/server/testkit/tests/testkit/group.rs
+++ b/server/testkit/tests/testkit/group.rs
@@ -4,7 +4,7 @@ use kanidmd_testkit::{create_user, ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
 use serde_json::Value;
 
 #[kanidmd_testkit::test]
-async fn test_v1_group_id_patch(rsclient: KanidmClient) {
+async fn test_v1_group_id_patch(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
@@ -25,7 +25,7 @@ async fn test_v1_group_id_patch(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_v1_group_id_attr_post(rsclient: KanidmClient) {
+async fn test_v1_group_id_attr_post(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
diff --git a/server/testkit/tests/testkit/http_manifest.rs b/server/testkit/tests/testkit/http_manifest.rs
index fb46d8f35..0e642abf4 100644
--- a/server/testkit/tests/testkit/http_manifest.rs
+++ b/server/testkit/tests/testkit/http_manifest.rs
@@ -1,7 +1,7 @@
 use kanidm_client::{http::header, KanidmClient};
 
 #[kanidmd_testkit::test]
-async fn test_https_manifest(rsclient: KanidmClient) {
+async fn test_https_manifest(rsclient: &KanidmClient) {
     // We need to do manual reqwests here.
     let client = rsclient.client();
 
diff --git a/server/testkit/tests/testkit/https_extractors.rs b/server/testkit/tests/testkit/https_extractors.rs
index 6fd6bb288..b664517cb 100644
--- a/server/testkit/tests/testkit/https_extractors.rs
+++ b/server/testkit/tests/testkit/https_extractors.rs
@@ -11,7 +11,7 @@ const DEFAULT_IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
 // *test where we don't trust the x-forwarded-for header
 
 #[kanidmd_testkit::test(trust_x_forward_for = false)]
-async fn dont_trust_xff_send_header(rsclient: KanidmClient) {
+async fn dont_trust_xff_send_header(rsclient: &KanidmClient) {
     let client = rsclient.client();
 
     let res = client
@@ -32,7 +32,7 @@ async fn dont_trust_xff_send_header(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test(trust_x_forward_for = false)]
-async fn dont_trust_xff_dont_send_header(rsclient: KanidmClient) {
+async fn dont_trust_xff_dont_send_header(rsclient: &KanidmClient) {
     let client = rsclient.client();
 
     let res = client
@@ -58,7 +58,7 @@ async fn dont_trust_xff_dont_send_header(rsclient: KanidmClient) {
 // *test where we trust the x-forwarded-for header
 
 #[kanidmd_testkit::test(trust_x_forward_for = true)]
-async fn trust_xff_send_invalid_header_single_value(rsclient: KanidmClient) {
+async fn trust_xff_send_invalid_header_single_value(rsclient: &KanidmClient) {
     let client = rsclient.client();
 
     let res = client
@@ -78,7 +78,7 @@ async fn trust_xff_send_invalid_header_single_value(rsclient: KanidmClient) {
 // with a valid leftmost address and an invalid address later in the list. Right now it wouldn't work.
 //
 #[kanidmd_testkit::test(trust_x_forward_for = true)]
-async fn trust_xff_send_invalid_header_multiple_values(rsclient: KanidmClient) {
+async fn trust_xff_send_invalid_header_multiple_values(rsclient: &KanidmClient) {
     let client = rsclient.client();
 
     let res = client
@@ -95,7 +95,7 @@ async fn trust_xff_send_invalid_header_multiple_values(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test(trust_x_forward_for = true)]
-async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: KanidmClient) {
+async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: &KanidmClient) {
     let ip_addr = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
 
     let client = rsclient.client();
@@ -115,7 +115,7 @@ async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: KanidmClient)
 }
 
 #[kanidmd_testkit::test(trust_x_forward_for = true)]
-async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: KanidmClient) {
+async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: &KanidmClient) {
     let ip_addr = "203.0.113.195";
 
     let client = rsclient.client();
@@ -135,7 +135,7 @@ async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: KanidmClient)
 }
 
 #[kanidmd_testkit::test(trust_x_forward_for = true)]
-async fn trust_xff_send_valid_header_multiple_address(rsclient: KanidmClient) {
+async fn trust_xff_send_valid_header_multiple_address(rsclient: &KanidmClient) {
     let first_ip_addr = "203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348";
 
     let client = rsclient.client();
@@ -176,7 +176,7 @@ async fn trust_xff_send_valid_header_multiple_address(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test(trust_x_forward_for = true)]
-async fn trust_xff_dont_send_header(rsclient: KanidmClient) {
+async fn trust_xff_dont_send_header(rsclient: &KanidmClient) {
     let client = rsclient.client();
 
     let res = client
diff --git a/server/testkit/tests/testkit/https_middleware.rs b/server/testkit/tests/testkit/https_middleware.rs
index 0d33d12f3..393034e6b 100644
--- a/server/testkit/tests/testkit/https_middleware.rs
+++ b/server/testkit/tests/testkit/https_middleware.rs
@@ -2,7 +2,7 @@ use kanidm_client::http::header;
 use kanidm_client::KanidmClient;
 
 #[kanidmd_testkit::test]
-async fn test_https_middleware_headers(rsclient: KanidmClient) {
+async fn test_https_middleware_headers(rsclient: &KanidmClient) {
     // We need to do manual reqwests here.
     let client = rsclient.client();
 
diff --git a/server/testkit/tests/testkit/identity_verification_tests.rs b/server/testkit/tests/testkit/identity_verification_tests.rs
index 285c908ab..2ed48a816 100644
--- a/server/testkit/tests/testkit/identity_verification_tests.rs
+++ b/server/testkit/tests/testkit/identity_verification_tests.rs
@@ -15,7 +15,7 @@ static USER_B_NAME: &str = "valid_user_b";
 // These tests check that invalid requests return the expected error
 
 #[kanidmd_testkit::test]
-async fn test_not_authenticated(rsclient: KanidmClient) {
+async fn test_not_authenticated(rsclient: &KanidmClient) {
     // basically here we try a bit of all the possible combinations while unauthenticated to check it's not working
     setup_server(&rsclient).await;
     create_user(&rsclient, USER_A_NAME).await;
@@ -46,7 +46,7 @@ async fn test_not_authenticated(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_non_existing_user_id(rsclient: KanidmClient) {
+async fn test_non_existing_user_id(rsclient: &KanidmClient) {
     setup_server(&rsclient).await;
     create_user(&rsclient, USER_A_NAME).await;
     create_user(&rsclient, USER_B_NAME).await;
@@ -86,7 +86,7 @@ async fn test_non_existing_user_id(rsclient: KanidmClient) {
 // error cases have already been tested in the previous section!
 // Each tests is named like `test_{api input}_response_{expected api output}_or_{expected api output}`
 #[kanidmd_testkit::test]
-async fn test_start_response_identity_verification_available(rsclient: KanidmClient) {
+async fn test_start_response_identity_verification_available(rsclient: &KanidmClient) {
     setup_server(&rsclient).await;
     create_user(&rsclient, USER_A_NAME).await;
     login_with_user(&rsclient, USER_A_NAME).await;
@@ -105,7 +105,7 @@ async fn test_start_response_identity_verification_available(rsclient: KanidmCli
 // this function tests both possible POSITIVE outcomes if we start from
 // `Start`, that is WaitForCode or ProvideCode
 #[kanidmd_testkit::test]
-async fn test_start_response_wait_for_code_or_provide_code(rsclient: KanidmClient) {
+async fn test_start_response_wait_for_code_or_provide_code(rsclient: &KanidmClient) {
     setup_server(&rsclient).await;
     let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
     let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
@@ -129,7 +129,7 @@ async fn test_start_response_wait_for_code_or_provide_code(rsclient: KanidmClien
 }
 
 #[kanidmd_testkit::test]
-async fn test_provide_code_response_code_failure_or_provide_code(rsclient: KanidmClient) {
+async fn test_provide_code_response_code_failure_or_provide_code(rsclient: &KanidmClient) {
     setup_server(&rsclient).await;
     let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
     let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
@@ -157,7 +157,7 @@ async fn test_provide_code_response_code_failure_or_provide_code(rsclient: Kanid
 
 // here we actually test the full idm flow by duplicating the server
 #[kanidmd_testkit::test]
-async fn test_full_identification_flow(rsclient: KanidmClient) {
+async fn test_full_identification_flow(rsclient: &KanidmClient) {
     setup_server(&rsclient).await;
     let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
     let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
@@ -175,12 +175,12 @@ async fn test_full_identification_flow(rsclient: KanidmClient) {
             (
                 valid_user_a_client,
                 USER_A_NAME,
-                valid_user_b_client,
+                &valid_user_b_client,
                 USER_B_NAME,
             )
         } else {
             (
-                valid_user_b_client,
+                &valid_user_b_client,
                 USER_B_NAME,
                 valid_user_a_client,
                 USER_A_NAME,
diff --git a/server/testkit/tests/testkit/integration.rs b/server/testkit/tests/testkit/integration.rs
index 4d2afb65f..4b2b2eac7 100644
--- a/server/testkit/tests/testkit/integration.rs
+++ b/server/testkit/tests/testkit/integration.rs
@@ -66,7 +66,7 @@ async fn get_webdriver_client() -> fantoccini::Client {
 
 #[kanidmd_testkit::test]
 #[cfg(feature = "webdriver")]
-async fn test_webdriver_user_login(rsclient: kanidm_client::KanidmClient) {
+async fn test_webdriver_user_login(rsclient: &KanidmClient) {
     if !cfg!(feature = "webdriver") {
         println!("Skipping test as webdriver feature is not enabled!");
         return;
@@ -206,7 +206,7 @@ async fn test_webdriver_user_login(rsclient: kanidm_client::KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_domain_reset_token_key(rsclient: KanidmClient) {
+async fn test_domain_reset_token_key(rsclient: &KanidmClient) {
     login_put_admin_idm_admins(&rsclient).await;
 
     let token = rsclient.get_token().await.expect("No bearer token present");
@@ -219,7 +219,7 @@ async fn test_domain_reset_token_key(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
+async fn test_idm_domain_set_ldap_basedn(rsclient: &KanidmClient) {
     login_put_admin_idm_admins(&rsclient).await;
     assert!(rsclient
         .idm_domain_set_ldap_basedn("dc=krabsarekool,dc=example,dc=com")
@@ -232,7 +232,7 @@ async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
+async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: &KanidmClient) {
     login_put_admin_idm_admins(&rsclient).await;
     assert!(rsclient
         .idm_domain_set_ldap_max_queryable_attrs(20)
@@ -246,7 +246,7 @@ async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
 
 #[kanidmd_testkit::test]
 /// Checks that a built-in group idm_all_persons has the "builtin" class as expected.
-async fn test_all_persons_has_builtin_class(rsclient: KanidmClient) {
+async fn test_all_persons_has_builtin_class(rsclient: &KanidmClient) {
     login_put_admin_idm_admins(&rsclient).await;
     let res = rsclient
         .idm_group_get("idm_all_persons")
diff --git a/server/testkit/tests/testkit/ldap_basic.rs b/server/testkit/tests/testkit/ldap_basic.rs
new file mode 100644
index 000000000..928390e35
--- /dev/null
+++ b/server/testkit/tests/testkit/ldap_basic.rs
@@ -0,0 +1,16 @@
+use kanidmd_testkit::AsyncTestEnvironment;
+use ldap3_client::LdapClientBuilder;
+
+#[kanidmd_testkit::test(ldap = true)]
+async fn test_ldap_basic_unix_bind(test_env: &AsyncTestEnvironment) {
+    let ldap_url = test_env.ldap_url.as_ref().unwrap();
+
+    let mut ldap_client = LdapClientBuilder::new(ldap_url).build().await.unwrap();
+
+    // Bind as anonymous
+    ldap_client.bind("".into(), "".into()).await.unwrap();
+
+    let whoami = ldap_client.whoami().await.unwrap();
+
+    assert_eq!(whoami, Some("u: anonymous@localhost".to_string()));
+}
diff --git a/server/testkit/tests/testkit/mod.rs b/server/testkit/tests/testkit/mod.rs
index 8c70d5166..2784a85ed 100644
--- a/server/testkit/tests/testkit/mod.rs
+++ b/server/testkit/tests/testkit/mod.rs
@@ -6,6 +6,7 @@ mod https_extractors;
 mod https_middleware;
 mod identity_verification_tests;
 mod integration;
+mod ldap_basic;
 mod mtls_test;
 mod oauth2_test;
 mod person;
diff --git a/server/testkit/tests/testkit/oauth2_test.rs b/server/testkit/tests/testkit/oauth2_test.rs
index 80cd2d083..8de7dab73 100644
--- a/server/testkit/tests/testkit/oauth2_test.rs
+++ b/server/testkit/tests/testkit/oauth2_test.rs
@@ -40,7 +40,7 @@ use kanidmd_testkit::{
 ///   If `true`, use the `code` passed in the callback URI's fragment, and
 ///   require the query parameter to be empty.
 async fn test_oauth2_openid_basic_flow_impl(
-    rsclient: KanidmClient,
+    rsclient: &KanidmClient,
     response_mode: Option<&str>,
     response_in_fragment: bool,
 ) {
@@ -535,7 +535,7 @@ async fn test_oauth2_openid_basic_flow_impl(
 ///
 /// The response should be returned as a query parameter.
 #[kanidmd_testkit::test]
-async fn test_oauth2_openid_basic_flow_mode_unset(rsclient: KanidmClient) {
+async fn test_oauth2_openid_basic_flow_mode_unset(rsclient: &KanidmClient) {
     test_oauth2_openid_basic_flow_impl(rsclient, None, false).await;
 }
 
@@ -544,7 +544,7 @@ async fn test_oauth2_openid_basic_flow_mode_unset(rsclient: KanidmClient) {
 ///
 /// The response should be returned as a query parameter.
 #[kanidmd_testkit::test]
-async fn test_oauth2_openid_basic_flow_mode_query(rsclient: KanidmClient) {
+async fn test_oauth2_openid_basic_flow_mode_query(rsclient: &KanidmClient) {
     test_oauth2_openid_basic_flow_impl(rsclient, Some("query"), false).await;
 }
 
@@ -553,7 +553,7 @@ async fn test_oauth2_openid_basic_flow_mode_query(rsclient: KanidmClient) {
 ///
 /// The response should be returned in the URI's fragment.
 #[kanidmd_testkit::test]
-async fn test_oauth2_openid_basic_flow_mode_fragment(rsclient: KanidmClient) {
+async fn test_oauth2_openid_basic_flow_mode_fragment(rsclient: &KanidmClient) {
     test_oauth2_openid_basic_flow_impl(rsclient, Some("fragment"), true).await;
 }
 
@@ -570,7 +570,7 @@ async fn test_oauth2_openid_basic_flow_mode_fragment(rsclient: KanidmClient) {
 ///   If `true`, use the `code` passed in the callback URI's fragment, and
 ///   require the query parameter to be empty.
 async fn test_oauth2_openid_public_flow_impl(
-    rsclient: KanidmClient,
+    rsclient: &KanidmClient,
     response_mode: Option<&str>,
     response_in_fragment: bool,
 ) {
@@ -901,7 +901,7 @@ async fn test_oauth2_openid_public_flow_impl(
 ///
 /// The response should be returned as a query parameter.
 #[kanidmd_testkit::test]
-async fn test_oauth2_openid_public_flow_mode_unset(rsclient: KanidmClient) {
+async fn test_oauth2_openid_public_flow_mode_unset(rsclient: &KanidmClient) {
     test_oauth2_openid_public_flow_impl(rsclient, None, false).await;
 }
 
@@ -910,7 +910,7 @@ async fn test_oauth2_openid_public_flow_mode_unset(rsclient: KanidmClient) {
 ///
 /// The response should be returned as a query parameter.
 #[kanidmd_testkit::test]
-async fn test_oauth2_openid_public_flow_mode_query(rsclient: KanidmClient) {
+async fn test_oauth2_openid_public_flow_mode_query(rsclient: &KanidmClient) {
     test_oauth2_openid_public_flow_impl(rsclient, Some("query"), false).await;
 }
 
@@ -919,12 +919,12 @@ async fn test_oauth2_openid_public_flow_mode_query(rsclient: KanidmClient) {
 ///
 /// The response should be returned in the URI's fragment.
 #[kanidmd_testkit::test]
-async fn test_oauth2_openid_public_flow_mode_fragment(rsclient: KanidmClient) {
+async fn test_oauth2_openid_public_flow_mode_fragment(rsclient: &KanidmClient) {
     test_oauth2_openid_public_flow_impl(rsclient, Some("fragment"), true).await;
 }
 
 #[kanidmd_testkit::test]
-async fn test_oauth2_token_post_bad_bodies(rsclient: KanidmClient) {
+async fn test_oauth2_token_post_bad_bodies(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
@@ -960,7 +960,7 @@ async fn test_oauth2_token_post_bad_bodies(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_oauth2_token_revoke_post(rsclient: KanidmClient) {
+async fn test_oauth2_token_revoke_post(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
diff --git a/server/testkit/tests/testkit/person.rs b/server/testkit/tests/testkit/person.rs
index 8e4bf95c9..621cec3d4 100644
--- a/server/testkit/tests/testkit/person.rs
+++ b/server/testkit/tests/testkit/person.rs
@@ -4,7 +4,7 @@ use kanidmd_testkit::{create_user, ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
 use serde_json::Value;
 
 #[kanidmd_testkit::test]
-async fn test_v1_person_id_patch(rsclient: KanidmClient) {
+async fn test_v1_person_id_patch(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
@@ -25,7 +25,7 @@ async fn test_v1_person_id_patch(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_v1_person_id_ssh_pubkeys_post(rsclient: KanidmClient) {
+async fn test_v1_person_id_ssh_pubkeys_post(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
diff --git a/server/testkit/tests/testkit/proto_v1_test.rs b/server/testkit/tests/testkit/proto_v1_test.rs
index 48ea88706..590b9910d 100644
--- a/server/testkit/tests/testkit/proto_v1_test.rs
+++ b/server/testkit/tests/testkit/proto_v1_test.rs
@@ -29,7 +29,7 @@ use kanidmd_testkit::{ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
 const UNIX_TEST_PASSWORD: &str = "unix test user password";
 
 #[kanidmd_testkit::test]
-async fn test_server_create(rsclient: KanidmClient) {
+async fn test_server_create(rsclient: &KanidmClient) {
     let e: Entry = serde_json::from_str(
         r#"{
             "attrs": {
@@ -55,7 +55,7 @@ async fn test_server_create(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_whoami_anonymous(rsclient: KanidmClient) {
+async fn test_server_whoami_anonymous(rsclient: &KanidmClient) {
     // First show we are un-authenticated.
     let pre_res = rsclient.whoami().await;
     // This means it was okay whoami, but no uat attached.
@@ -84,7 +84,7 @@ async fn test_server_whoami_anonymous(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_whoami_admin_simple_password(rsclient: KanidmClient) {
+async fn test_server_whoami_admin_simple_password(rsclient: &KanidmClient) {
     // First show we are un-authenticated.
     let pre_res = rsclient.whoami().await;
     // This means it was okay whoami, but no uat attached.
@@ -109,7 +109,7 @@ async fn test_server_whoami_admin_simple_password(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_search(rsclient: KanidmClient) {
+async fn test_server_search(rsclient: &KanidmClient) {
     // First show we are un-authenticated.
     let pre_res = rsclient.whoami().await;
     // This means it was okay whoami, but no uat attached.
@@ -135,7 +135,7 @@ async fn test_server_search(rsclient: KanidmClient) {
 
 // test the rest group endpoint.
 #[kanidmd_testkit::test]
-async fn test_server_rest_group_read(rsclient: KanidmClient) {
+async fn test_server_rest_group_read(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -151,7 +151,7 @@ async fn test_server_rest_group_read(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_group_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -263,7 +263,7 @@ async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_account_read(rsclient: KanidmClient) {
+async fn test_server_rest_account_read(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -279,7 +279,7 @@ async fn test_server_rest_account_read(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_schema_read(rsclient: KanidmClient) {
+async fn test_server_rest_schema_read(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -313,7 +313,7 @@ async fn test_server_rest_schema_read(rsclient: KanidmClient) {
 
 // Test resetting a radius cred, and then checking/viewing it.
 #[kanidmd_testkit::test]
-async fn test_server_radius_credential_lifecycle(rsclient: KanidmClient) {
+async fn test_server_radius_credential_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -384,7 +384,7 @@ async fn test_server_radius_credential_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_person_account_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_person_account_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -439,7 +439,7 @@ async fn test_server_rest_person_account_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_sshkey_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_sshkey_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -509,7 +509,7 @@ async fn test_server_rest_sshkey_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_domain_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_domain_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -539,7 +539,7 @@ async fn test_server_rest_domain_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_posix_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_posix_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -660,7 +660,7 @@ async fn test_server_rest_posix_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_posix_auth_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_posix_auth_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -760,7 +760,7 @@ async fn test_server_rest_posix_auth_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_recycle_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_recycle_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -814,7 +814,7 @@ async fn test_server_rest_recycle_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
+async fn test_server_rest_oauth2_basic_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -1027,7 +1027,7 @@ async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_credential_update_session_pw(rsclient: KanidmClient) {
+async fn test_server_credential_update_session_pw(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -1102,7 +1102,7 @@ async fn test_server_credential_update_session_pw(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_credential_update_session_totp_pw(rsclient: KanidmClient) {
+async fn test_server_credential_update_session_totp_pw(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
@@ -1365,7 +1365,7 @@ async fn setup_demo_account_password(
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_credential_update_session_passkey(rsclient: KanidmClient) {
+async fn test_server_credential_update_session_passkey(rsclient: &KanidmClient) {
     let mut wa = setup_demo_account_passkey(&rsclient).await;
 
     let res = rsclient
@@ -1383,7 +1383,7 @@ async fn test_server_credential_update_session_passkey(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
+async fn test_server_api_token_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
@@ -1566,7 +1566,7 @@ async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
+async fn test_server_user_auth_token_lifecycle(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
@@ -1689,7 +1689,7 @@ async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_user_auth_reauthentication(rsclient: KanidmClient) {
+async fn test_server_user_auth_reauthentication(rsclient: &KanidmClient) {
     let mut wa = setup_demo_account_passkey(&rsclient).await;
 
     let res = rsclient
@@ -1868,7 +1868,7 @@ async fn start_password_session(
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_user_auth_unprivileged(rsclient: KanidmClient) {
+async fn test_server_user_auth_unprivileged(rsclient: &KanidmClient) {
     let (account_name, account_pass) = setup_demo_account_password(&rsclient)
         .await
         .expect("Failed to setup demo_account");
@@ -1891,7 +1891,7 @@ async fn test_server_user_auth_unprivileged(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_server_user_auth_privileged_shortcut(rsclient: KanidmClient) {
+async fn test_server_user_auth_privileged_shortcut(rsclient: &KanidmClient) {
     let (account_name, account_pass) = setup_demo_account_password(&rsclient)
         .await
         .expect("Failed to setup demo_account");
diff --git a/server/testkit/tests/testkit/scim_test.rs b/server/testkit/tests/testkit/scim_test.rs
index 8e947790f..8bd9acc72 100644
--- a/server/testkit/tests/testkit/scim_test.rs
+++ b/server/testkit/tests/testkit/scim_test.rs
@@ -9,7 +9,7 @@ use std::str::FromStr;
 use url::Url;
 
 #[kanidmd_testkit::test]
-async fn test_sync_account_lifecycle(rsclient: KanidmClient) {
+async fn test_sync_account_lifecycle(rsclient: &KanidmClient) {
     let a_res = rsclient
         .auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
         .await;
@@ -104,7 +104,7 @@ async fn test_sync_account_lifecycle(rsclient: KanidmClient) {
 }
 
 #[kanidmd_testkit::test]
-async fn test_scim_sync_entry_get(rsclient: KanidmClient) {
+async fn test_scim_sync_entry_get(rsclient: &KanidmClient) {
     let res = rsclient
         .auth_simple_password("admin", ADMIN_TEST_PASSWORD)
         .await;
diff --git a/server/testkit/tests/testkit/service_account.rs b/server/testkit/tests/testkit/service_account.rs
index 1fed6b3aa..278e229dd 100644
--- a/server/testkit/tests/testkit/service_account.rs
+++ b/server/testkit/tests/testkit/service_account.rs
@@ -2,7 +2,7 @@ use kanidm_client::KanidmClient;
 
 /// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
 #[kanidmd_testkit::test]
-async fn test_v1_service_account_id_attr_attr_delete(rsclient: KanidmClient) {
+async fn test_v1_service_account_id_attr_attr_delete(rsclient: &KanidmClient) {
     // We need to do manual reqwests here.
     let client = rsclient.client();
 
diff --git a/server/testkit/tests/testkit/system.rs b/server/testkit/tests/testkit/system.rs
index d0d7f46c3..80aa69813 100644
--- a/server/testkit/tests/testkit/system.rs
+++ b/server/testkit/tests/testkit/system.rs
@@ -2,7 +2,7 @@ use kanidm_client::KanidmClient;
 
 /// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
 #[kanidmd_testkit::test]
-async fn test_v1_system_post_attr(rsclient: KanidmClient) {
+async fn test_v1_system_post_attr(rsclient: &KanidmClient) {
     let client = rsclient.client();
 
     let response = match client
diff --git a/server/testkit/tests/testkit/unix.rs b/server/testkit/tests/testkit/unix.rs
index f3ea98c6d..bc0d86300 100644
--- a/server/testkit/tests/testkit/unix.rs
+++ b/server/testkit/tests/testkit/unix.rs
@@ -3,8 +3,8 @@ use kanidmd_lib::constants::NAME_IDM_ADMINS;
 use kanidmd_testkit::*;
 
 #[kanidmd_testkit::test]
-async fn account_id_unix_token(rsclient: KanidmClient) {
-    login_put_admin_idm_admins(&rsclient).await;
+async fn account_id_unix_token(rsclient: &KanidmClient) {
+    login_put_admin_idm_admins(rsclient).await;
 
     create_user(&rsclient, "group_manager", "idm_group_manage_priv").await;
     // create test user without creating new groups