diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs
index 360cb86f..18404986 100644
--- a/actix-http/src/lib.rs
+++ b/actix-http/src/lib.rs
@@ -25,6 +25,7 @@
 )]
 #![doc(html_logo_url = "https://actix.rs/img/logo.png")]
 #![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
+#![cfg_attr(docsrs, feature(doc_cfg))]
 
 pub use ::http::{uri, uri::Uri};
 pub use ::http::{Method, StatusCode, Version};
@@ -69,6 +70,8 @@ pub use self::payload::{BoxedPayloadStream, Payload, PayloadStream};
 pub use self::requests::{Request, RequestHead, RequestHeadType};
 pub use self::responses::{Response, ResponseBuilder, ResponseHead};
 pub use self::service::HttpService;
+#[cfg(any(feature = "openssl", feature = "rustls"))]
+pub use self::service::TlsAcceptorConfig;
 
 /// A major HTTP protocol version.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/actix-http/src/service.rs b/actix-http/src/service.rs
index f4fe625a..27029cb8 100644
--- a/actix-http/src/service.rs
+++ b/actix-http/src/service.rs
@@ -181,6 +181,25 @@ where
     }
 }
 
+/// Configuration options used when accepting TLS connection.
+#[cfg(any(feature = "openssl", feature = "rustls"))]
+#[cfg_attr(docsrs, doc(cfg(any(feature = "openssl", feature = "rustls"))))]
+#[derive(Debug, Default)]
+pub struct TlsAcceptorConfig {
+    pub(crate) handshake_timeout: Option<std::time::Duration>,
+}
+
+#[cfg(any(feature = "openssl", feature = "rustls"))]
+impl TlsAcceptorConfig {
+    /// Set TLS handshake timeout duration.
+    pub fn handshake_timeout(self, dur: std::time::Duration) -> Self {
+        Self {
+            handshake_timeout: Some(dur),
+            // ..self
+        }
+    }
+}
+
 #[cfg(feature = "openssl")]
 mod openssl {
     use actix_service::ServiceFactoryExt as _;
@@ -230,7 +249,28 @@ mod openssl {
             Error = TlsError<SslError, DispatchError>,
             InitError = (),
         > {
-            Acceptor::new(acceptor)
+            self.openssl_with_config(acceptor, TlsAcceptorConfig::default())
+        }
+
+        /// Create OpenSSL based service with custom TLS acceptor configuration.
+        pub fn openssl_with_config(
+            self,
+            acceptor: SslAcceptor,
+            tls_acceptor_config: TlsAcceptorConfig,
+        ) -> impl ServiceFactory<
+            TcpStream,
+            Config = (),
+            Response = (),
+            Error = TlsError<SslError, DispatchError>,
+            InitError = (),
+        > {
+            let mut acceptor = Acceptor::new(acceptor);
+
+            if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
+                acceptor.set_handshake_timeout(handshake_timeout);
+            }
+
+            acceptor
                 .map_init_err(|_| {
                     unreachable!("TLS acceptor service factory does not error on init")
                 })
@@ -293,8 +333,23 @@ mod rustls {
     {
         /// Create Rustls based service.
         pub fn rustls(
+            self,
+            config: ServerConfig,
+        ) -> impl ServiceFactory<
+            TcpStream,
+            Config = (),
+            Response = (),
+            Error = TlsError<io::Error, DispatchError>,
+            InitError = (),
+        > {
+            self.rustls_with_config(config, TlsAcceptorConfig::default())
+        }
+
+        /// Create Rustls based service with custom TLS acceptor configuration.
+        pub fn rustls_with_config(
             self,
             mut config: ServerConfig,
+            tls_acceptor_config: TlsAcceptorConfig,
         ) -> impl ServiceFactory<
             TcpStream,
             Config = (),
@@ -306,7 +361,13 @@ mod rustls {
             protos.extend_from_slice(&config.alpn_protocols);
             config.alpn_protocols = protos;
 
-            Acceptor::new(config)
+            let mut acceptor = Acceptor::new(config);
+
+            if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
+                acceptor.set_handshake_timeout(handshake_timeout);
+            }
+
+            acceptor
                 .map_init_err(|_| {
                     unreachable!("TLS acceptor service factory does not error on init")
                 })
diff --git a/actix-http/tests/test_openssl.rs b/actix-http/tests/test_openssl.rs
index 35321ac9..b97b2e45 100644
--- a/actix-http/tests/test_openssl.rs
+++ b/actix-http/tests/test_openssl.rs
@@ -2,13 +2,13 @@
 
 extern crate tls_openssl as openssl;
 
-use std::{convert::Infallible, io};
+use std::{convert::Infallible, io, time::Duration};
 
 use actix_http::{
     body::{BodyStream, BoxBody, SizedStream},
     error::PayloadError,
     header::{self, HeaderValue},
-    Error, HttpService, Method, Request, Response, StatusCode, Version,
+    Error, HttpService, Method, Request, Response, StatusCode, TlsAcceptorConfig, Version,
 };
 use actix_http_test::test_server;
 use actix_service::{fn_service, ServiceFactoryExt};
@@ -89,7 +89,10 @@ async fn h2_1() -> io::Result<()> {
                 assert_eq!(req.version(), Version::HTTP_2);
                 ok::<_, Error>(Response::ok())
             })
-            .openssl(tls_config())
+            .openssl_with_config(
+                tls_config(),
+                TlsAcceptorConfig::default().handshake_timeout(Duration::from_secs(5)),
+            )
             .map_err(|_| ())
     })
     .await;
diff --git a/actix-http/tests/test_rustls.rs b/actix-http/tests/test_rustls.rs
index 55037529..2bbf1524 100644
--- a/actix-http/tests/test_rustls.rs
+++ b/actix-http/tests/test_rustls.rs
@@ -8,13 +8,14 @@ use std::{
     net::{SocketAddr, TcpStream as StdTcpStream},
     sync::Arc,
     task::Poll,
+    time::Duration,
 };
 
 use actix_http::{
     body::{BodyStream, BoxBody, SizedStream},
     error::PayloadError,
     header::{self, HeaderName, HeaderValue},
-    Error, HttpService, Method, Request, Response, StatusCode, Version,
+    Error, HttpService, Method, Request, Response, StatusCode, TlsAcceptorConfig, Version,
 };
 use actix_http_test::test_server;
 use actix_rt::pin;
@@ -160,7 +161,10 @@ async fn h2_1() -> io::Result<()> {
                 assert_eq!(req.version(), Version::HTTP_2);
                 ok::<_, Error>(Response::ok())
             })
-            .rustls(tls_config())
+            .rustls_with_config(
+                tls_config(),
+                TlsAcceptorConfig::default().handshake_timeout(Duration::from_secs(5)),
+            )
     })
     .await;
 
diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md
index 3fa2f8f2..0144cb91 100644
--- a/actix-web/CHANGES.md
+++ b/actix-web/CHANGES.md
@@ -1,12 +1,17 @@
 # Changelog
 
 ## Unreleased - 2022-xx-xx
-- Minimum supported Rust version (MSRV) is now 1.57 due to transitive `time` dependency.
 ### Added
 - Add `ServiceRequest::{parts, request}()` getter methods. [#2786]
+- Add configuration options for TLS handshake timeout via `HttpServer::{rustls, openssl}_with_config` methods. [#2752]
 
+### Changed
+- Minimum supported Rust version (MSRV) is now 1.57 due to transitive `time` dependency.
+
+[#2752]: https://github.com/actix/actix-web/pull/2752
 [#2786]: https://github.com/actix/actix-web/pull/2786
 
+
 ## 4.1.0 - 2022-06-11
 ### Added
 - Add `ServiceRequest::extract()` to make it easier to use extractors when writing middlewares. [#2647]
diff --git a/actix-web/src/server.rs b/actix-web/src/server.rs
index 99812600..169eafab 100644
--- a/actix-web/src/server.rs
+++ b/actix-web/src/server.rs
@@ -18,6 +18,9 @@ use actix_tls::accept::openssl::reexports::{AlpnError, SslAcceptor, SslAcceptorB
 #[cfg(feature = "rustls")]
 use actix_tls::accept::rustls::reexports::ServerConfig as RustlsServerConfig;
 
+#[cfg(any(feature = "openssl", feature = "rustls"))]
+use actix_http::TlsAcceptorConfig;
+
 use crate::{config::AppConfig, Error};
 
 struct Socket {
@@ -30,6 +33,8 @@ struct Config {
     keep_alive: KeepAlive,
     client_request_timeout: Duration,
     client_disconnect_timeout: Duration,
+    #[cfg(any(feature = "openssl", feature = "rustls"))]
+    tls_handshake_timeout: Option<Duration>,
 }
 
 /// An HTTP Server.
@@ -92,6 +97,8 @@ where
                 keep_alive: KeepAlive::default(),
                 client_request_timeout: Duration::from_secs(5),
                 client_disconnect_timeout: Duration::from_secs(1),
+                #[cfg(any(feature = "rustls", feature = "openssl"))]
+                tls_handshake_timeout: None,
             })),
             backlog: 1024,
             sockets: Vec::new(),
@@ -225,6 +232,24 @@ where
         self
     }
 
+    /// Set TLS handshake timeout.
+    ///
+    /// Defines a timeout for TLS handshake. If the TLS handshake does not complete
+    /// within this time, the connection is closed.
+    ///
+    /// By default handshake timeout is set to 3000 milliseconds.
+    #[cfg(any(feature = "openssl", feature = "rustls"))]
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "openssl", feature = "rustls"))))]
+    pub fn tls_handshake_timeout(self, dur: Duration) -> Self {
+        self.config
+            .lock()
+            .unwrap()
+            .tls_handshake_timeout
+            .replace(dur);
+
+        self
+    }
+
     #[doc(hidden)]
     #[deprecated(since = "4.0.0", note = "Renamed to `client_disconnect_timeout`.")]
     pub fn client_shutdown(self, dur: u64) -> Self {
@@ -376,10 +401,15 @@ where
                         .into_factory()
                         .map_err(|err| err.into().error_response());
 
+                    let acceptor_config = match c.tls_handshake_timeout {
+                        Some(dur) => TlsAcceptorConfig::default().handshake_timeout(dur),
+                        None => TlsAcceptorConfig::default(),
+                    };
+
                     svc.finish(map_config(fac, move |_| {
                         AppConfig::new(true, host.clone(), addr)
                     }))
-                    .openssl(acceptor.clone())
+                    .openssl_with_config(acceptor.clone(), acceptor_config)
                 })?;
 
         Ok(self)
@@ -434,10 +464,15 @@ where
                         .into_factory()
                         .map_err(|err| err.into().error_response());
 
+                    let acceptor_config = match c.tls_handshake_timeout {
+                        Some(dur) => TlsAcceptorConfig::default().handshake_timeout(dur),
+                        None => TlsAcceptorConfig::default(),
+                    };
+
                     svc.finish(map_config(fac, move |_| {
                         AppConfig::new(true, host.clone(), addr)
                     }))
-                    .rustls(config.clone())
+                    .rustls_with_config(config.clone(), acceptor_config)
                 })?;
 
         Ok(self)