diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 733c6d73d270988cd3d993b0951a6b7e6c547522..ec5c5267142a909e19730619d15f33266312671e 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -2877,13 +2877,13 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "0.2.3"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747"
+checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
 dependencies = [
  "bytes",
  "fnv",
- "itoa 0.4.8",
+ "itoa 1.0.1",
 ]
 
 [[package]]
@@ -3134,9 +3134,9 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11e017217fcd18da0a25296d3693153dd19c8a6aadab330b3595285d075385d1"
+checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a"
 dependencies = [
  "jsonrpsee-core",
  "jsonrpsee-http-server",
@@ -3149,9 +3149,9 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-client-transport"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce395539a14d3ad4ec1256fde105abd36a2da25d578a291cabe98f45adfdb111"
+checksum = "8752740ecd374bcbf8b69f3e80b0327942df76f793f8d4e60d3355650c31fb74"
 dependencies = [
  "futures-util",
  "http",
@@ -3170,9 +3170,9 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-core"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16efcd4477de857d4a2195a45769b2fe9ebb54f3ef5a4221d3b014a4fe33ec0b"
+checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca"
 dependencies = [
  "anyhow",
  "arrayvec 0.7.2",
@@ -3183,6 +3183,7 @@ dependencies = [
  "futures-timer",
  "futures-util",
  "globset",
+ "http",
  "hyper",
  "jsonrpsee-types",
  "lazy_static",
@@ -3195,14 +3196,15 @@ dependencies = [
  "thiserror",
  "tokio",
  "tracing",
+ "tracing-futures",
  "unicase",
 ]
 
 [[package]]
 name = "jsonrpsee-http-server"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdd69efeb3ce2cba767f126872f4eeb4624038a29098e75d77608b2b4345ad03"
+checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117"
 dependencies = [
  "futures-channel",
  "futures-util",
@@ -3213,13 +3215,14 @@ dependencies = [
  "serde_json",
  "tokio",
  "tracing",
+ "tracing-futures",
 ]
 
 [[package]]
 name = "jsonrpsee-proc-macros"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "874cf3f6a027cebf36cae767feca9aa2e8a8f799880e49eb5540819fcbd8eada"
+checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -3229,9 +3232,9 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-types"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bcf76cd316f5d3ad48138085af1f45e2c58c98e02f0779783dbb034d43f7c86"
+checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d"
 dependencies = [
  "anyhow",
  "beef",
@@ -3243,10 +3246,11 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-ws-client"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee043cb5dd0d51d3eb93432e998d5bae797691a7b10ec4a325e036bcdb48c48a"
+checksum = "6ee5feddd5188e62ac08fcf0e56478138e581509d4730f3f7be9b57dd402a4ff"
 dependencies = [
+ "http",
  "jsonrpsee-client-transport",
  "jsonrpsee-core",
  "jsonrpsee-types",
@@ -3254,12 +3258,13 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-ws-server"
-version = "0.14.0"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bd2e4d266774a671f8def3794255b28eddd09b18d76e0b913fa439f34588c0a"
+checksum = "d488ba74fb369e5ab68926feb75a483458b88e768d44319f37e4ecad283c7325"
 dependencies = [
  "futures-channel",
  "futures-util",
+ "http",
  "jsonrpsee-core",
  "jsonrpsee-types",
  "serde_json",
@@ -3268,6 +3273,7 @@ dependencies = [
  "tokio-stream",
  "tokio-util",
  "tracing",
+ "tracing-futures",
 ]
 
 [[package]]
@@ -10839,9 +10845,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
 
 [[package]]
 name = "tracing"
-version = "0.1.29"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
+checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
 dependencies = [
  "cfg-if 1.0.0",
  "log",
@@ -10852,9 +10858,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.18"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
+checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml
index c8e74ea9515ac7e8f890aec4ccbcfb30c9aa6b66..eeba198da82122f3162fbfa1fcd2a0c1c1d38f60 100644
--- a/substrate/bin/node-template/node/Cargo.toml
+++ b/substrate/bin/node-template/node/Cargo.toml
@@ -42,7 +42,7 @@ frame-system = { version = "4.0.0-dev", path = "../../../frame/system" }
 pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../frame/transaction-payment" }
 
 # These dependencies are used for the node template's RPCs
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" }
 sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
 sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" }
diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml
index 9dde225c0d6fb75452bfc2677f6d9a2566e9d8af..fe7c5332e2b45db82e02aab53d08df0b16941803 100644
--- a/substrate/bin/node/cli/Cargo.toml
+++ b/substrate/bin/node/cli/Cargo.toml
@@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"]
 clap = { version = "3.1.18", features = ["derive"], optional = true }
 codec = { package = "parity-scale-codec", version = "3.0.0" }
 serde = { version = "1.0.136", features = ["derive"] }
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 futures = "0.3.21"
 hex-literal = "0.3.4"
 log = "0.4.17"
diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml
index 547d0df7a83725d5e5b9bb53b73f59a064eb7729..07b25085b9d104ac5475e335336b70a7b1572552 100644
--- a/substrate/bin/node/rpc/Cargo.toml
+++ b/substrate/bin/node/rpc/Cargo.toml
@@ -11,7 +11,7 @@ repository = "https://github.com/paritytech/substrate/"
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 node-primitives = { version = "2.0.0", path = "../primitives" }
 pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" }
 pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" }
diff --git a/substrate/client/beefy/rpc/Cargo.toml b/substrate/client/beefy/rpc/Cargo.toml
index 7d31aea3f69715da2c3829d115e997472729df62..46ee7640d710a3ac1d9d2359d264c4420a485993 100644
--- a/substrate/client/beefy/rpc/Cargo.toml
+++ b/substrate/client/beefy/rpc/Cargo.toml
@@ -11,7 +11,7 @@ homepage = "https://substrate.io"
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] }
 futures = "0.3.21"
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 log = "0.4"
 parking_lot = "0.12.0"
 serde = { version = "1.0.136", features = ["derive"] }
diff --git a/substrate/client/beefy/rpc/src/lib.rs b/substrate/client/beefy/rpc/src/lib.rs
index 13bca08d37429baccb763169e8445e1348482c06..91ff59324bd95ff30b5dd00a88290efd42da32d2 100644
--- a/substrate/client/beefy/rpc/src/lib.rs
+++ b/substrate/client/beefy/rpc/src/lib.rs
@@ -30,8 +30,8 @@ use futures::{task::SpawnError, FutureExt, StreamExt};
 use jsonrpsee::{
 	core::{async_trait, Error as JsonRpseeError, RpcResult},
 	proc_macros::rpc,
-	types::{error::CallError, ErrorObject},
-	PendingSubscription,
+	types::{error::CallError, ErrorObject, SubscriptionResult},
+	SubscriptionSink,
 };
 use log::warn;
 
@@ -135,19 +135,18 @@ impl<Block> BeefyApiServer<notification::EncodedSignedCommitment, Block::Hash> f
 where
 	Block: BlockT,
 {
-	fn subscribe_justifications(&self, pending: PendingSubscription) {
+	fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult {
 		let stream = self
 			.signed_commitment_stream
 			.subscribe()
 			.map(|sc| notification::EncodedSignedCommitment::new::<Block>(sc));
 
 		let fut = async move {
-			if let Some(mut sink) = pending.accept() {
-				sink.pipe_from_stream(stream).await;
-			}
+			sink.pipe_from_stream(stream).await;
 		};
 
 		self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed());
+		Ok(())
 	}
 
 	async fn latest_finalized(&self) -> RpcResult<Block::Hash> {
@@ -197,9 +196,9 @@ mod tests {
 		let (rpc, _) = setup_io_handler();
 		let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#;
 		let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#.to_string();
-		let (result, _) = rpc.raw_json_request(&request).await.unwrap();
+		let (response, _) = rpc.raw_json_request(&request).await.unwrap();
 
-		assert_eq!(expected_response, result,);
+		assert_eq!(expected_response, response.result);
 	}
 
 	#[tokio::test]
@@ -229,8 +228,8 @@ mod tests {
 		let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2);
 		while std::time::Instant::now() < deadline {
 			let (response, _) = io.raw_json_request(request).await.expect("RPC requests work");
-			if response != not_ready {
-				assert_eq!(response, expected);
+			if response.result != not_ready {
+				assert_eq!(response.result, expected);
 				// Success
 				return
 			}
@@ -260,7 +259,7 @@ mod tests {
 			.unwrap();
 		let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
 
-		assert_eq!(response, expected);
+		assert_eq!(response.result, expected);
 	}
 
 	fn create_commitment() -> BeefySignedCommitment<Block> {
diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml
index 4c9350735d529efe7cca91227896f858d6958e44..488036277d7b6ad9c4c32dddc06f23dca93b5bb5 100644
--- a/substrate/client/consensus/babe/rpc/Cargo.toml
+++ b/substrate/client/consensus/babe/rpc/Cargo.toml
@@ -13,7 +13,7 @@ readme = "README.md"
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 futures = "0.3.21"
 serde = { version = "1.0.136", features = ["derive"] }
 thiserror = "1.0"
diff --git a/substrate/client/consensus/babe/rpc/src/lib.rs b/substrate/client/consensus/babe/rpc/src/lib.rs
index af19d410346e3e9bda5086f1d52e795ab2e6acf1..b000d38a44f02fa93cadd823ddd8fb0188520f32 100644
--- a/substrate/client/consensus/babe/rpc/src/lib.rs
+++ b/substrate/client/consensus/babe/rpc/src/lib.rs
@@ -262,7 +262,7 @@ mod tests {
 		let (response, _) = api.raw_json_request(request).await.unwrap();
 		let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#;
 
-		assert_eq!(&response, expected);
+		assert_eq!(&response.result, expected);
 	}
 
 	#[tokio::test]
@@ -274,6 +274,6 @@ mod tests {
 		let (response, _) = api.raw_json_request(request).await.unwrap();
 		let expected = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#;
 
-		assert_eq!(&response, expected);
+		assert_eq!(&response.result, expected);
 	}
 }
diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml
index 7aa2232178f2275ebbbfd7e411365e0c518a33ff..83c156ef5667f97cd2937f50d0319de3b6c44ece 100644
--- a/substrate/client/consensus/manual-seal/Cargo.toml
+++ b/substrate/client/consensus/manual-seal/Cargo.toml
@@ -13,7 +13,7 @@ readme = "README.md"
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 assert_matches = "1.3.0"
 async-trait = "0.1.50"
 codec = { package = "parity-scale-codec", version = "3.0.0" }
diff --git a/substrate/client/finality-grandpa/rpc/Cargo.toml b/substrate/client/finality-grandpa/rpc/Cargo.toml
index f2d37da058f451fbde37a5a3e1c6ac50942a3471..075179d3ceaf7c1925417b92a664330434fa031f 100644
--- a/substrate/client/finality-grandpa/rpc/Cargo.toml
+++ b/substrate/client/finality-grandpa/rpc/Cargo.toml
@@ -12,7 +12,7 @@ homepage = "https://substrate.io"
 [dependencies]
 finality-grandpa = { version = "0.16.0", features = ["derive-codec"] }
 futures = "0.3.16"
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 log = "0.4.8"
 parity-scale-codec = { version = "3.0.0", features = ["derive"] }
 serde = { version = "1.0.105", features = ["derive"] }
diff --git a/substrate/client/finality-grandpa/rpc/src/lib.rs b/substrate/client/finality-grandpa/rpc/src/lib.rs
index 1cf23a18c794baed9148404f567b70920a3bed05..85df72de77b544d545351ab5485904ff5b1503c5 100644
--- a/substrate/client/finality-grandpa/rpc/src/lib.rs
+++ b/substrate/client/finality-grandpa/rpc/src/lib.rs
@@ -26,7 +26,8 @@ use std::sync::Arc;
 use jsonrpsee::{
 	core::{async_trait, RpcResult},
 	proc_macros::rpc,
-	PendingSubscription,
+	types::SubscriptionResult,
+	SubscriptionSink,
 };
 
 mod error;
@@ -102,7 +103,7 @@ where
 		ReportedRoundStates::from(&self.authority_set, &self.voter_state).map_err(Into::into)
 	}
 
-	fn subscribe_justifications(&self, pending: PendingSubscription) {
+	fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult {
 		let stream = self.justification_stream.subscribe().map(
 			|x: sc_finality_grandpa::GrandpaJustification<Block>| {
 				JustificationNotification::from(x)
@@ -110,12 +111,11 @@ where
 		);
 
 		let fut = async move {
-			if let Some(mut sink) = pending.accept() {
-				sink.pipe_from_stream(stream).await;
-			}
+			sink.pipe_from_stream(stream).await;
 		};
 
 		self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed());
+		Ok(())
 	}
 
 	async fn prove_finality(
@@ -283,9 +283,9 @@ mod tests {
 		let (rpc, _) = setup_io_handler(EmptyVoterState);
 		let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":0}"#.to_string();
 		let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#;
-		let (result, _) = rpc.raw_json_request(&request).await.unwrap();
+		let (response, _) = rpc.raw_json_request(&request).await.unwrap();
 
-		assert_eq!(expected_response, result,);
+		assert_eq!(expected_response, response.result);
 	}
 
 	#[tokio::test]
@@ -306,8 +306,8 @@ mod tests {
 		},\"id\":0}".to_string();
 
 		let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#;
-		let (result, _) = rpc.raw_json_request(&request).await.unwrap();
-		assert_eq!(expected_response, result);
+		let (response, _) = rpc.raw_json_request(&request).await.unwrap();
+		assert_eq!(expected_response, response.result);
 	}
 
 	#[tokio::test]
@@ -328,7 +328,7 @@ mod tests {
 			.unwrap();
 		let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
 
-		assert_eq!(response, expected);
+		assert_eq!(response.result, expected);
 	}
 
 	fn create_justification() -> GrandpaJustification<Block> {
diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml
index 3425ba2b245df9ebf133f0a6df2c3318c010135c..101d558663f9f634ff695c5ee975ccbae3e445e0 100644
--- a/substrate/client/rpc-api/Cargo.toml
+++ b/substrate/client/rpc-api/Cargo.toml
@@ -28,4 +28,4 @@ sp-rpc = { version = "6.0.0", path = "../../primitives/rpc" }
 sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" }
 sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" }
 sp-version = { version = "5.0.0", path = "../../primitives/version" }
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml
index daaa955839045def4f7c2874e743b51bb341c18e..8b40972527be82da1b9aeb15aab6286b7826a2b4 100644
--- a/substrate/client/rpc-servers/Cargo.toml
+++ b/substrate/client/rpc-servers/Cargo.toml
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 futures = "0.3.21"
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 log = "0.4.17"
 serde_json = "1.0.79"
 tokio = { version = "1.17.0", features = ["parking_lot"] }
diff --git a/substrate/client/rpc-servers/src/middleware.rs b/substrate/client/rpc-servers/src/middleware.rs
index cb9918268f4defdaa76d447d0458b69261548045..1c0660fc3528d80c3704b6521516c3a98d2a4fb6 100644
--- a/substrate/client/rpc-servers/src/middleware.rs
+++ b/substrate/client/rpc-servers/src/middleware.rs
@@ -18,11 +18,12 @@
 
 //! RPC middlware to collect prometheus metrics on RPC calls.
 
-use jsonrpsee::core::middleware::Middleware;
+use jsonrpsee::core::middleware::{Headers, HttpMiddleware, MethodKind, Params, WsMiddleware};
 use prometheus_endpoint::{
 	register, Counter, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry,
 	U64,
 };
+use std::net::SocketAddr;
 
 /// Metrics for RPC middleware storing information about the number of requests started/completed,
 /// calls started/completed and their timings.
@@ -134,30 +135,33 @@ impl RpcMiddleware {
 	pub fn new(metrics: RpcMetrics, transport_label: &'static str) -> Self {
 		Self { metrics, transport_label }
 	}
-}
-
-impl Middleware for RpcMiddleware {
-	type Instant = std::time::Instant;
-
-	fn on_connect(&self) {
-		self.metrics.ws_sessions_opened.as_ref().map(|counter| counter.inc());
-	}
 
-	fn on_request(&self) -> Self::Instant {
+	/// Called when a new JSON-RPC request comes to the server.
+	fn on_request(&self) -> std::time::Instant {
 		let now = std::time::Instant::now();
 		self.metrics.requests_started.with_label_values(&[self.transport_label]).inc();
 		now
 	}
 
-	fn on_call(&self, name: &str) {
-		log::trace!(target: "rpc_metrics", "[{}] on_call name={}", self.transport_label, name);
+	/// Called on each JSON-RPC method call, batch requests will trigger `on_call` multiple times.
+	fn on_call(&self, name: &str, params: Params, kind: MethodKind) {
+		log::trace!(
+			target: "rpc_metrics",
+			"[{}] on_call name={} params={:?} kind={}",
+			self.transport_label,
+			name,
+			params,
+			kind,
+		);
 		self.metrics
 			.calls_started
 			.with_label_values(&[self.transport_label, name])
 			.inc();
 	}
 
-	fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) {
+	/// Called on each JSON-RPC method completion, batch requests will trigger `on_result` multiple
+	/// times.
+	fn on_result(&self, name: &str, success: bool, started_at: std::time::Instant) {
 		let micros = started_at.elapsed().as_micros();
 		log::debug!(
 			target: "rpc_metrics",
@@ -183,12 +187,57 @@ impl Middleware for RpcMiddleware {
 			.inc();
 	}
 
-	fn on_response(&self, started_at: Self::Instant) {
+	/// Called once the JSON-RPC request is finished and response is sent to the output buffer.
+	fn on_response(&self, _result: &str, started_at: std::time::Instant) {
 		log::trace!(target: "rpc_metrics", "[{}] on_response started_at={:?}", self.transport_label, started_at);
 		self.metrics.requests_finished.with_label_values(&[self.transport_label]).inc();
 	}
+}
+
+impl WsMiddleware for RpcMiddleware {
+	type Instant = std::time::Instant;
+
+	fn on_connect(&self, _remote_addr: SocketAddr, _headers: &Headers) {
+		self.metrics.ws_sessions_opened.as_ref().map(|counter| counter.inc());
+	}
+
+	fn on_request(&self) -> Self::Instant {
+		self.on_request()
+	}
+
+	fn on_call(&self, name: &str, params: Params, kind: MethodKind) {
+		self.on_call(name, params, kind)
+	}
+
+	fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) {
+		self.on_result(name, success, started_at)
+	}
+
+	fn on_response(&self, _result: &str, started_at: Self::Instant) {
+		self.on_response(_result, started_at)
+	}
 
-	fn on_disconnect(&self) {
+	fn on_disconnect(&self, _remote_addr: SocketAddr) {
 		self.metrics.ws_sessions_closed.as_ref().map(|counter| counter.inc());
 	}
 }
+
+impl HttpMiddleware for RpcMiddleware {
+	type Instant = std::time::Instant;
+
+	fn on_request(&self, _remote_addr: SocketAddr, _headers: &Headers) -> Self::Instant {
+		self.on_request()
+	}
+
+	fn on_call(&self, name: &str, params: Params, kind: MethodKind) {
+		self.on_call(name, params, kind)
+	}
+
+	fn on_result(&self, name: &str, success: bool, started_at: Self::Instant) {
+		self.on_result(name, success, started_at)
+	}
+
+	fn on_response(&self, _result: &str, started_at: Self::Instant) {
+		self.on_response(_result, started_at)
+	}
+}
diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml
index e8c657f1a29493af6ca36706583a687ee56dea84..5a05ae6e29df10396d14bdfbaf0605f377b9e787 100644
--- a/substrate/client/rpc/Cargo.toml
+++ b/substrate/client/rpc/Cargo.toml
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
 futures = "0.3.21"
 hash-db = { version = "0.15.2", default-features = false }
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 lazy_static = { version = "1.4.0", optional = true }
 log = "0.4.17"
 parking_lot = "0.12.0"
diff --git a/substrate/client/rpc/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs
index b8c4f5d582808373e8740845c97abab260ce1afe..7d0ffdc62e080c0644358d5d3f4aecbba661f93a 100644
--- a/substrate/client/rpc/src/author/mod.rs
+++ b/substrate/client/rpc/src/author/mod.rs
@@ -29,7 +29,8 @@ use codec::{Decode, Encode};
 use futures::{FutureExt, TryFutureExt};
 use jsonrpsee::{
 	core::{async_trait, Error as JsonRpseeError, RpcResult},
-	PendingSubscription,
+	types::SubscriptionResult,
+	SubscriptionSink,
 };
 use sc_rpc_api::DenyUnsafe;
 use sc_transaction_pool_api::{
@@ -176,13 +177,13 @@ where
 			.collect())
 	}
 
-	fn watch_extrinsic(&self, pending: PendingSubscription, xt: Bytes) {
+	fn watch_extrinsic(&self, mut sink: SubscriptionSink, xt: Bytes) -> SubscriptionResult {
 		let best_block_hash = self.client.info().best_hash;
 		let dxt = match TransactionFor::<P>::decode(&mut &xt[..]).map_err(|e| Error::from(e)) {
 			Ok(dxt) => dxt,
 			Err(e) => {
-				pending.reject(JsonRpseeError::from(e));
-				return
+				let _ = sink.reject(JsonRpseeError::from(e));
+				return Ok(())
 			},
 		};
 
@@ -199,19 +200,15 @@ where
 			let stream = match submit.await {
 				Ok(stream) => stream,
 				Err(err) => {
-					pending.reject(JsonRpseeError::from(err));
+					let _ = sink.reject(JsonRpseeError::from(err));
 					return
 				},
 			};
 
-			let mut sink = match pending.accept() {
-				Some(sink) => sink,
-				_ => return,
-			};
-
 			sink.pipe_from_stream(stream).await;
 		};
 
 		self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed());
+		Ok(())
 	}
 }
diff --git a/substrate/client/rpc/src/chain/chain_full.rs b/substrate/client/rpc/src/chain/chain_full.rs
index c00c6e5875d94834c7a6e48d67e421e23009bc00..375e724a33d69575495ef3affeffedd029cd5068 100644
--- a/substrate/client/rpc/src/chain/chain_full.rs
+++ b/substrate/client/rpc/src/chain/chain_full.rs
@@ -26,7 +26,7 @@ use futures::{
 	future::{self, FutureExt},
 	stream::{self, Stream, StreamExt},
 };
-use jsonrpsee::PendingSubscription;
+use jsonrpsee::SubscriptionSink;
 use sc_client_api::{BlockBackend, BlockchainEvents};
 use sp_blockchain::HeaderBackend;
 use sp_runtime::{
@@ -69,7 +69,7 @@ where
 		self.client.block(&BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err)
 	}
 
-	fn subscribe_all_heads(&self, sink: PendingSubscription) {
+	fn subscribe_all_heads(&self, sink: SubscriptionSink) {
 		subscribe_headers(
 			&self.client,
 			&self.executor,
@@ -83,7 +83,7 @@ where
 		)
 	}
 
-	fn subscribe_new_heads(&self, sink: PendingSubscription) {
+	fn subscribe_new_heads(&self, sink: SubscriptionSink) {
 		subscribe_headers(
 			&self.client,
 			&self.executor,
@@ -98,7 +98,7 @@ where
 		)
 	}
 
-	fn subscribe_finalized_heads(&self, sink: PendingSubscription) {
+	fn subscribe_finalized_heads(&self, sink: SubscriptionSink) {
 		subscribe_headers(
 			&self.client,
 			&self.executor,
@@ -117,7 +117,7 @@ where
 fn subscribe_headers<Block, Client, F, G, S>(
 	client: &Arc<Client>,
 	executor: &SubscriptionTaskExecutor,
-	pending: PendingSubscription,
+	mut sink: SubscriptionSink,
 	best_block_hash: G,
 	stream: F,
 ) where
@@ -143,9 +143,7 @@ fn subscribe_headers<Block, Client, F, G, S>(
 	let stream = stream::iter(maybe_header).chain(stream());
 
 	let fut = async move {
-		if let Some(mut sink) = pending.accept() {
-			sink.pipe_from_stream(stream).await;
-		}
+		sink.pipe_from_stream(stream).await;
 	};
 
 	executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed());
diff --git a/substrate/client/rpc/src/chain/mod.rs b/substrate/client/rpc/src/chain/mod.rs
index a300c80271fd191bd016a065ac18af7520e939ff..be06b91ca747fe3c741b81f489518216730838d7 100644
--- a/substrate/client/rpc/src/chain/mod.rs
+++ b/substrate/client/rpc/src/chain/mod.rs
@@ -27,7 +27,7 @@ use std::sync::Arc;
 
 use crate::SubscriptionTaskExecutor;
 
-use jsonrpsee::{core::RpcResult, PendingSubscription};
+use jsonrpsee::{core::RpcResult, types::SubscriptionResult, SubscriptionSink};
 use sc_client_api::BlockchainEvents;
 use sp_rpc::{list::ListOrValue, number::NumberOrHex};
 use sp_runtime::{
@@ -95,13 +95,13 @@ where
 	}
 
 	/// All new head subscription
-	fn subscribe_all_heads(&self, sink: PendingSubscription);
+	fn subscribe_all_heads(&self, sink: SubscriptionSink);
 
 	/// New best head subscription
-	fn subscribe_new_heads(&self, sink: PendingSubscription);
+	fn subscribe_new_heads(&self, sink: SubscriptionSink);
 
 	/// Finalized head subscription
-	fn subscribe_finalized_heads(&self, sink: PendingSubscription);
+	fn subscribe_finalized_heads(&self, sink: SubscriptionSink);
 }
 
 /// Create new state API that works on full node.
@@ -160,16 +160,19 @@ where
 		self.backend.finalized_head().map_err(Into::into)
 	}
 
-	fn subscribe_all_heads(&self, sink: PendingSubscription) {
-		self.backend.subscribe_all_heads(sink)
+	fn subscribe_all_heads(&self, sink: SubscriptionSink) -> SubscriptionResult {
+		self.backend.subscribe_all_heads(sink);
+		Ok(())
 	}
 
-	fn subscribe_new_heads(&self, sink: PendingSubscription) {
-		self.backend.subscribe_new_heads(sink)
+	fn subscribe_new_heads(&self, sink: SubscriptionSink) -> SubscriptionResult {
+		self.backend.subscribe_new_heads(sink);
+		Ok(())
 	}
 
-	fn subscribe_finalized_heads(&self, sink: PendingSubscription) {
-		self.backend.subscribe_finalized_heads(sink)
+	fn subscribe_finalized_heads(&self, sink: SubscriptionSink) -> SubscriptionResult {
+		self.backend.subscribe_finalized_heads(sink);
+		Ok(())
 	}
 }
 
diff --git a/substrate/client/rpc/src/dev/tests.rs b/substrate/client/rpc/src/dev/tests.rs
index b7a0de8f5ae0b452c963cd9d5b115fa196f5940f..f3b18690d09725e8ca5a2e7966e2f4162556993b 100644
--- a/substrate/client/rpc/src/dev/tests.rs
+++ b/substrate/client/rpc/src/dev/tests.rs
@@ -17,8 +17,6 @@
 // along with this program. If not, see <https://www.gnu.org/licenses/>.
 
 use super::*;
-use assert_matches::assert_matches;
-use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError};
 use sc_block_builder::BlockBuilderProvider;
 use sp_blockchain::HeaderBackend;
 use sp_consensus::BlockOrigin;
@@ -61,9 +59,18 @@ async fn deny_unsafe_works() {
 	let block = client.new_block(Default::default()).unwrap().build().unwrap().block;
 	client.import(BlockOrigin::Own, block).await.unwrap();
 
-	assert_matches!(
-		api.call::<_, Option<BlockStats>>("dev_getBlockStats", [client.info().best_hash])
-			.await,
-		Err(JsonRpseeError::Call(CallError::Custom(err))) if err.message().contains("RPC call is unsafe to be called externally")
+	let best_hash = client.info().best_hash;
+	let best_hash_param =
+		serde_json::to_string(&best_hash).expect("To string must always succeed for block hashes");
+
+	let request = format!(
+		"{{\"jsonrpc\":\"2.0\",\"method\":\"dev_getBlockStats\",\"params\":[{}],\"id\":1}}",
+		best_hash_param
+	);
+	let (resp, _) = api.raw_json_request(&request).await.expect("Raw calls should succeed");
+
+	assert_eq!(
+		resp.result,
+		r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#
 	);
 }
diff --git a/substrate/client/rpc/src/state/mod.rs b/substrate/client/rpc/src/state/mod.rs
index 232be4edc8aab172efa2708d4c0f0508f6d67905..7213e4360ae2b3ed35fcf19595aa406263a2ac5d 100644
--- a/substrate/client/rpc/src/state/mod.rs
+++ b/substrate/client/rpc/src/state/mod.rs
@@ -29,7 +29,8 @@ use crate::SubscriptionTaskExecutor;
 
 use jsonrpsee::{
 	core::{Error as JsonRpseeError, RpcResult},
-	ws_server::PendingSubscription,
+	types::SubscriptionResult,
+	ws_server::SubscriptionSink,
 };
 
 use sc_rpc_api::{state::ReadProof, DenyUnsafe};
@@ -155,10 +156,10 @@ where
 	) -> Result<sp_rpc::tracing::TraceBlockResponse, Error>;
 
 	/// New runtime version subscription
-	fn subscribe_runtime_version(&self, sink: PendingSubscription);
+	fn subscribe_runtime_version(&self, sink: SubscriptionSink);
 
 	/// New storage subscription
-	fn subscribe_storage(&self, sink: PendingSubscription, keys: Option<Vec<StorageKey>>);
+	fn subscribe_storage(&self, sink: SubscriptionSink, keys: Option<Vec<StorageKey>>);
 }
 
 /// Create new state API that works on full node.
@@ -318,19 +319,25 @@ where
 			.map_err(Into::into)
 	}
 
-	fn subscribe_runtime_version(&self, sink: PendingSubscription) {
-		self.backend.subscribe_runtime_version(sink)
+	fn subscribe_runtime_version(&self, sink: SubscriptionSink) -> SubscriptionResult {
+		self.backend.subscribe_runtime_version(sink);
+		Ok(())
 	}
 
-	fn subscribe_storage(&self, sink: PendingSubscription, keys: Option<Vec<StorageKey>>) {
+	fn subscribe_storage(
+		&self,
+		mut sink: SubscriptionSink,
+		keys: Option<Vec<StorageKey>>,
+	) -> SubscriptionResult {
 		if keys.is_none() {
 			if let Err(err) = self.deny_unsafe.check_if_safe() {
 				let _ = sink.reject(JsonRpseeError::from(err));
-				return
+				return Ok(())
 			}
 		}
 
-		self.backend.subscribe_storage(sink, keys)
+		self.backend.subscribe_storage(sink, keys);
+		Ok(())
 	}
 }
 
diff --git a/substrate/client/rpc/src/state/state_full.rs b/substrate/client/rpc/src/state/state_full.rs
index 5a8a83cdd4851cd3b74918a5040d48df61ec254f..42ba70b0af7e7a9ec45eb15dc7f31c25728ca7a2 100644
--- a/substrate/client/rpc/src/state/state_full.rs
+++ b/substrate/client/rpc/src/state/state_full.rs
@@ -28,7 +28,7 @@ use super::{
 use crate::SubscriptionTaskExecutor;
 
 use futures::{future, stream, FutureExt, StreamExt};
-use jsonrpsee::{core::Error as JsonRpseeError, PendingSubscription};
+use jsonrpsee::{core::Error as JsonRpseeError, SubscriptionSink};
 use sc_client_api::{
 	Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider,
 	StorageProvider,
@@ -357,7 +357,7 @@ where
 			.map_err(client_err)
 	}
 
-	fn subscribe_runtime_version(&self, pending: PendingSubscription) {
+	fn subscribe_runtime_version(&self, mut sink: SubscriptionSink) {
 		let client = self.client.clone();
 
 		let initial = match self
@@ -369,7 +369,7 @@ where
 		{
 			Ok(initial) => initial,
 			Err(e) => {
-				pending.reject(JsonRpseeError::from(e));
+				let _ = sink.reject(JsonRpseeError::from(e));
 				return
 			},
 		};
@@ -397,19 +397,17 @@ where
 		let stream = futures::stream::once(future::ready(initial)).chain(version_stream);
 
 		let fut = async move {
-			if let Some(mut sink) = pending.accept() {
-				sink.pipe_from_stream(stream).await;
-			}
+			sink.pipe_from_stream(stream).await;
 		};
 
 		self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed());
 	}
 
-	fn subscribe_storage(&self, pending: PendingSubscription, keys: Option<Vec<StorageKey>>) {
+	fn subscribe_storage(&self, mut sink: SubscriptionSink, keys: Option<Vec<StorageKey>>) {
 		let stream = match self.client.storage_changes_notification_stream(keys.as_deref(), None) {
 			Ok(stream) => stream,
 			Err(blockchain_err) => {
-				pending.reject(JsonRpseeError::from(Error::Client(Box::new(blockchain_err))));
+				let _ = sink.reject(JsonRpseeError::from(Error::Client(Box::new(blockchain_err))));
 				return
 			},
 		};
@@ -442,9 +440,7 @@ where
 			.filter(|storage| future::ready(!storage.changes.is_empty()));
 
 		let fut = async move {
-			if let Some(mut sink) = pending.accept() {
-				sink.pipe_from_stream(stream).await;
-			}
+			sink.pipe_from_stream(stream).await;
 		};
 
 		self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed());
diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml
index 31b0c860cf19018daf83618e46d6564c59b72211..e8ddf40a0ae03148bc75e686e194aa00c12549e3 100644
--- a/substrate/client/service/Cargo.toml
+++ b/substrate/client/service/Cargo.toml
@@ -22,7 +22,7 @@ wasmtime = ["sc-executor/wasmtime"]
 test-helpers = []
 
 [dependencies]
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 thiserror = "1.0.30"
 futures = "0.3.21"
 rand = "0.7.3"
diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs
index 2e7b611ffb18747c13fcc24807689e96dac31279..98bcb17174157c8d80373599281b607b17ff3d93 100644
--- a/substrate/client/service/src/lib.rs
+++ b/substrate/client/service/src/lib.rs
@@ -101,7 +101,10 @@ impl RpcHandlers {
 		&self,
 		json_query: &str,
 	) -> Result<(String, mpsc::UnboundedReceiver<String>), JsonRpseeError> {
-		self.0.raw_json_request(json_query).await
+		self.0
+			.raw_json_request(json_query)
+			.await
+			.map(|(method_res, recv)| (method_res.result, recv))
 	}
 
 	/// Provides access to the underlying `RpcModule`
diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml
index bd9194092fa3df6c9bbe4cf73ac45e5e99be6f20..d02637fcf884b820da5505b270a0a707cb4735b2 100644
--- a/substrate/client/sync-state-rpc/Cargo.toml
+++ b/substrate/client/sync-state-rpc/Cargo.toml
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 serde = { version = "1.0.136", features = ["derive"] }
 serde_json = "1.0.79"
 thiserror = "1.0.30"
diff --git a/substrate/frame/contracts/rpc/Cargo.toml b/substrate/frame/contracts/rpc/Cargo.toml
index a81abef9f37ca20f1bcafb7a7829fb16351b1373..7876c7cba40d0b1342689cd1b33bd555f4a4144f 100644
--- a/substrate/frame/contracts/rpc/Cargo.toml
+++ b/substrate/frame/contracts/rpc/Cargo.toml
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 serde = { version = "1", features = ["derive"] }
 
 # Substrate Dependencies
diff --git a/substrate/frame/merkle-mountain-range/rpc/Cargo.toml b/substrate/frame/merkle-mountain-range/rpc/Cargo.toml
index 45cb975df277b44cf0dcb3f408a4ef4277b7a7f6..c7d966290474739fa6b856fc81262da64c98cdb8 100644
--- a/substrate/frame/merkle-mountain-range/rpc/Cargo.toml
+++ b/substrate/frame/merkle-mountain-range/rpc/Cargo.toml
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 serde = { version = "1.0.136", features = ["derive"] }
 sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
 sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
diff --git a/substrate/frame/transaction-payment/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml
index 31e0972a0d5b543ad988014479b1b99de792ade4..16c2cc55efefb62801d5dc9ba42243a71ab3b40d 100644
--- a/substrate/frame/transaction-payment/rpc/Cargo.toml
+++ b/substrate/frame/transaction-payment/rpc/Cargo.toml
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" }
 sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
 sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml
index a77d0902464217f5384371b5a2b51b8586e0db27..3121157df68d81152524c92f7d4d86551d049fc8 100644
--- a/substrate/utils/frame/remote-externalities/Cargo.toml
+++ b/substrate/utils/frame/remote-externalities/Cargo.toml
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
 env_logger = "0.9"
-jsonrpsee = { version = "0.14.0", features = ["ws-client", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["ws-client", "macros"] }
 log = "0.4.17"
 serde = "1.0.136"
 serde_json = "1.0"
diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml
index 6c6bc5cf327b5e7825afc3c97bf088d8d277bd94..00fdc87a506e87e8a0dcd2772672c617ee7f08d6 100644
--- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml
+++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml
@@ -25,7 +25,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" }
 sp-trie = { path = "../../../../primitives/trie" }
 trie-db = { version = "0.23.1" }
 
-jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
+jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 
 # Substrate Dependencies
 sc-client-api = { version = "4.0.0-dev", path = "../../../../client/api" }
diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml
index 7ea07534e1bdb66be5813395fa7b04d63b74e0c7..2104774bd2605b998a729f3a50ce2a46a17717b0 100644
--- a/substrate/utils/frame/rpc/support/Cargo.toml
+++ b/substrate/utils/frame/rpc/support/Cargo.toml
@@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0" }
 futures = "0.3.21"
-jsonrpsee = { version = "0.14.0", features = ["jsonrpsee-types"] }
+jsonrpsee = { version = "0.15.1", features = ["jsonrpsee-types"] }
 serde = "1"
 frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" }
 sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" }
@@ -25,6 +25,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" }
 
 [dev-dependencies]
 scale-info = "2.1.1"
-jsonrpsee = { version = "0.14.0", features = ["ws-client", "jsonrpsee-types"] }
+jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] }
 tokio = "1.17.0"
 frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" }
diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml
index f76944a0fec40cfe134f8e82f6b69349dbabd2e0..5d8984e8d399b2f3cc1f90574ed4f7b8cedfcc80 100644
--- a/substrate/utils/frame/rpc/system/Cargo.toml
+++ b/substrate/utils/frame/rpc/system/Cargo.toml
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 [dependencies]
 serde_json = "1"
 codec = { package = "parity-scale-codec", version = "3.0.0" }
-jsonrpsee = { version = "0.14.0", features = ["server"] }
+jsonrpsee = { version = "0.15.1", features = ["server"] }
 futures = "0.3.21"
 log = "0.4.17"
 frame-system-rpc-runtime-api = { version = "4.0.0-dev", path = "../../../../frame/system/rpc/runtime-api" }
diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml
index b82da0f1222a7309f8f5f628ef064efd5f3be599..4b4f9bdb2809ad39acaadf998987f8914197cc26 100644
--- a/substrate/utils/frame/try-runtime/cli/Cargo.toml
+++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml
@@ -19,7 +19,7 @@ parity-scale-codec = "3.0.0"
 serde = "1.0.136"
 zstd = { version = "0.11.2", default-features = false }
 remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" }
-jsonrpsee = { version = "0.14.0", default-features = false, features = ["ws-client"] }
+jsonrpsee = { version = "0.15.1", default-features = false, features = ["ws-client"] }
 sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" }
 sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" }
 sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" }