diff --git a/substrate/bin/node-template/node/src/cli.rs b/substrate/bin/node-template/node/src/cli.rs
index 15ceaa06230d15194fc63e05efde5984b7ca68ea..98037eb886a8ec04ee78bc8f0b21b2269872d0fc 100644
--- a/substrate/bin/node-template/node/src/cli.rs
+++ b/substrate/bin/node-template/node/src/cli.rs
@@ -41,12 +41,9 @@ pub enum Subcommand {
 	#[command(subcommand)]
 	Benchmark(frame_benchmarking_cli::BenchmarkCmd),
 
-	/// Try some command against runtime state.
-	#[cfg(feature = "try-runtime")]
-	TryRuntime(try_runtime_cli::TryRuntimeCmd),
-
-	/// Try some command against runtime state. Note: `try-runtime` feature must be enabled.
-	#[cfg(not(feature = "try-runtime"))]
+	/// Try-runtime has migrated to a standalone CLI
+	/// (<https://github.com/paritytech/try-runtime-cli>). The subcommand exists as a stub and
+	/// deprecation notice. It will be removed entirely some time after Janurary 2024.
 	TryRuntime,
 
 	/// Db meta columns information.
diff --git a/substrate/bin/node-template/node/src/command.rs b/substrate/bin/node-template/node/src/command.rs
index 8fc697b5f9c14694aafcdc2fad7beb106caae78d..a25157693cd4392072703c28b14310f16dc01030 100644
--- a/substrate/bin/node-template/node/src/command.rs
+++ b/substrate/bin/node-template/node/src/command.rs
@@ -10,9 +10,6 @@ use sc_cli::SubstrateCli;
 use sc_service::PartialComponents;
 use sp_keyring::Sr25519Keyring;
 
-#[cfg(feature = "try-runtime")]
-use try_runtime_cli::block_building_info::timestamp_with_aura_info;
-
 impl SubstrateCli for Cli {
 	fn impl_name() -> String {
 		"Substrate Node".into()
@@ -172,28 +169,7 @@ pub fn run() -> sc_cli::Result<()> {
 			})
 		},
 		#[cfg(feature = "try-runtime")]
-		Some(Subcommand::TryRuntime(cmd)) => {
-			use crate::service::ExecutorDispatch;
-			use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch};
-			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
-				// we don't need any of the components of new_partial, just a runtime, or a task
-				// manager to do `async_run`.
-				let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
-				let task_manager =
-					sc_service::TaskManager::new(config.tokio_handle.clone(), registry)
-						.map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
-				let info_provider = timestamp_with_aura_info(6000);
-
-				Ok((
-					cmd.run::<Block, ExtendedHostFunctions<
-						sp_io::SubstrateHostFunctions,
-						<ExecutorDispatch as NativeExecutionDispatch>::ExtendHostFunctions,
-					>, _>(Some(info_provider)),
-					task_manager,
-				))
-			})
-		},
+		Some(Subcommand::TryRuntime) => Err(try_runtime_cli::DEPRECATION_NOTICE.into()),
 		#[cfg(not(feature = "try-runtime"))]
 		Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \
 				You can enable it with `--features try-runtime`."
diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs
index 35b949831141d67a89cd91eb3d9f05eb2a816fac..4e0d6303870cba960ee42f77ed105c1021cbb380 100644
--- a/substrate/bin/node/cli/src/cli.rs
+++ b/substrate/bin/node/cli/src/cli.rs
@@ -57,12 +57,9 @@ pub enum Subcommand {
 	#[command(subcommand)]
 	Benchmark(frame_benchmarking_cli::BenchmarkCmd),
 
-	/// Try some command against runtime state.
-	#[cfg(feature = "try-runtime")]
-	TryRuntime(try_runtime_cli::TryRuntimeCmd),
-
-	/// Try some command against runtime state. Note: `try-runtime` feature must be enabled.
-	#[cfg(not(feature = "try-runtime"))]
+	/// Try-runtime has migrated to a standalone CLI
+	/// (<https://github.com/paritytech/try-runtime-cli>). The subcommand exists as a stub and
+	/// deprecation notice. It will be removed entirely some time after Janurary 2024.
 	TryRuntime,
 
 	/// Key management cli utilities
diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs
index b138b397eff6f679f2b5e898db4c3fa7dd654549..8fb413dba17780fd17a07bc47bc722ab833d98c2 100644
--- a/substrate/bin/node/cli/src/command.rs
+++ b/substrate/bin/node/cli/src/command.rs
@@ -32,12 +32,6 @@ use sp_keyring::Sr25519Keyring;
 
 use std::sync::Arc;
 
-#[cfg(feature = "try-runtime")]
-use {
-	kitchensink_runtime::constants::time::SLOT_DURATION,
-	try_runtime_cli::block_building_info::substrate_info,
-};
-
 impl SubstrateCli for Cli {
 	fn impl_name() -> String {
 		"Substrate Node".into()
@@ -227,28 +221,7 @@ pub fn run() -> Result<()> {
 			})
 		},
 		#[cfg(feature = "try-runtime")]
-		Some(Subcommand::TryRuntime(cmd)) => {
-			use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch};
-			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
-				// we don't need any of the components of new_partial, just a runtime, or a task
-				// manager to do `async_run`.
-				let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
-				let task_manager =
-					sc_service::TaskManager::new(config.tokio_handle.clone(), registry)
-						.map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
-
-				let info_provider = substrate_info(SLOT_DURATION);
-
-				Ok((
-					cmd.run::<Block, ExtendedHostFunctions<
-						sp_io::SubstrateHostFunctions,
-						<ExecutorDispatch as NativeExecutionDispatch>::ExtendHostFunctions,
-					>, _>(Some(info_provider)),
-					task_manager,
-				))
-			})
-		},
+		Some(Subcommand::TryRuntime) => Err(try_runtime_cli::DEPRECATION_NOTICE.into()),
 		#[cfg(not(feature = "try-runtime"))]
 		Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \
 				You can enable it with `--features try-runtime`."
diff --git a/substrate/scripts/ci/gitlab/pipeline/build.yml b/substrate/scripts/ci/gitlab/pipeline/build.yml
index e6ee1554663611817fc635aecd72857ae9529a1d..8f63f6ecc3911270d5b12000e1a94ab6df35ef52 100644
--- a/substrate/scripts/ci/gitlab/pipeline/build.yml
+++ b/substrate/scripts/ci/gitlab/pipeline/build.yml
@@ -15,6 +15,7 @@
   variables:
     RUSTFLAGS: "-D warnings"
   script:
+    - cargo install --locked --git https://github.com/paritytech/try-runtime-cli --rev a93c9b5abe5d31a4cf1936204f7e5c489184b521
     - git clone
       --depth=1
       --branch="$PIPELINE_SCRIPTS_TAG"
@@ -36,10 +37,9 @@
       substrate: polkadot-v*
       polkadot: release-v*
     COMPANION_CHECK_COMMAND: >
-      time cargo build --release -p "$NETWORK"-runtime &&
-      time cargo run --release --features try-runtime try-runtime \
+      time cargo build --release -p "$NETWORK"-runtime --features try-runtime &&
+      time try-runtime \
           --runtime ./target/release/wbuild/"$NETWORK"-runtime/target/wasm32-unknown-unknown/release/"$NETWORK"_runtime.wasm \
-          --chain=${NETWORK}-dev \
           on-runtime-upgrade --checks=pre-and-post live --uri wss://${NETWORK}-try-runtime-node.parity-chains.parity.io:443
 
 # Individual jobs are set up for each dependent project so that they can be ran in parallel.
diff --git a/substrate/utils/frame/try-runtime/cli/src/lib.rs b/substrate/utils/frame/try-runtime/cli/src/lib.rs
index fbc55ad1dce6fd46dcddce9714874c0d258c78ca..2adf6658795558ad5a2a9474df124bd572266cf8 100644
--- a/substrate/utils/frame/try-runtime/cli/src/lib.rs
+++ b/substrate/utils/frame/try-runtime/cli/src/lib.rs
@@ -17,338 +17,10 @@
 
 //! # Try-runtime
 //!
-//! Substrate's ultimate testing framework for the power users.
+//! Substrate's `try-runtime` subcommand has been migrated to a [standalone
+//! CLI](https://github.com/paritytech/try-runtime-cli).
 //!
-//! > As the name suggests, `try-runtime` is a detailed testing framework that gives you a lot of
-//! control over what is being executed in which environment. It is recommended that user's first
-//! familiarize themselves with substrate in depth, particularly the execution model. It is critical
-//! to deeply understand how the wasm/client/runtime interactions, and the runtime apis work in the
-//! substrate runtime, before commencing to working with `try-runtime`.
-//!
-//! #### Resources
-//!
-//! Some resources about the above:
-//!
-//! 1. <https://docs.substrate.io/reference/command-line-tools/try-runtime/>
-//! 2. <https://www.crowdcast.io/e/substrate-seminar/41>
-//! 3. <https://docs.substrate.io/fundamentals/runtime-development/>
-//!
-//! ---
-//!
-//! ## Background Knowledge
-//!
-//! The basis of all try-runtime commands is the same: connect to a live node, scrape its *state*
-//! and put it inside a `TestExternalities`, then call into a *specific runtime-api* using the given
-//! state and some *runtime*.
-//!
-//! Alternatively, the state could come from a snapshot file.
-//!
-//! All of the variables in the above statement are made *italic*. Let's look at each of them:
-//!
-//! 1. **State** is the key-value pairs of data that comprise the canonical information that any
-//!    blockchain is keeping. A state can be full (all key-value pairs), or be partial (only pairs
-//!    related to some pallets/prefixes). Moreover, some keys are especial and are not related to
-//!    specific pallets, known as [`well_known_keys`] in substrate. The most important of these is
-//!    the `:CODE:` key, which contains the code used for execution, when wasm execution is chosen.
-//!
-//! 2. *A runtime-api* call is a call into a function defined in the runtime, *on top of a given
-//!    state*. Each subcommand of `try-runtime` utilizes a specific *runtime-api*.
-//!
-//! 3. Finally, the **runtime** is the actual code that is used to execute the aforementioned
-//!    runtime-api. Everything in this crate assumes wasm execution, which means the runtime that
-//!    you use is the one stored onchain, namely under the `:CODE:` key.
-//!
-//! To recap, a typical try-runtime command does the following:
-//!
-//! 1. Download the state of a live chain, and write to an `externalities`.
-//! 2. Overwrite the `:CODE:` with a given wasm blob
-//! 3. Test some functionality via calling a runtime-api.
-//!
-//! ## Usage
-//!
-//! To use any of the provided commands, [`SharedParams`] must be provided. The most important of
-//! which being [`SharedParams::runtime`], which specifies which runtime to use. Furthermore,
-//! [`SharedParams::overwrite_state_version`] can be used to alter the state-version (see
-//! <https://forum.polkadot.network/t/state-trie-migration/852> for more info).
-//!
-//! Then, the specific command has to be specified. See [`Command`] for more information about each
-//! command's specific customization flags, and assumptions regarding the runtime being used.
-//!
-//! Said briefly, this CLI is capable of executing:
-//!
-//! * [`Command::OnRuntimeUpgrade`]: execute all the `on_runtime_upgrade` hooks.
-//! * [`Command::ExecuteBlock`]: re-execute the given block.
-//! * [`Command::OffchainWorker`]: re-execute the given block's offchain worker code path.
-//! * [`Command::FollowChain`]: continuously execute the blocks of a remote chain on top of a given
-//!   runtime.
-//! * [`Command::CreateSnapshot`]: Create a snapshot file from a remote node.
-//!
-//! Finally, To make sure there are no errors regarding this, always run any `try-runtime` command
-//! with `executor=trace` logging targets, which will specify which runtime is being used per api
-//! call. Moreover, `remote-ext`, `try-runtime` and `runtime` logs targets will also be useful.
-//!
-//! ## Spec name check
-//!
-//! A common pitfall is that you might be running some test on top of the state of chain `x`, with
-//! the runtime of chain `y`. To avoid this all commands do a spec-name check before executing
-//! anything by default. This will check the, if any alterations are being made to the `:CODE:`,
-//! then the spec names match. The spec versions are warned, but are not mandated to match.
-//!
-//! > If anything, in most cases, we expect spec-versions to NOT match, because try-runtime is all
-//! > about testing unreleased runtimes.
-//!
-//! ## Note on signature and state-root checks
-//!
-//! All of the commands calling into `TryRuntime_execute_block` ([`Command::ExecuteBlock`] and
-//! [`Command::FollowChain`]) disable both state root and signature checks. This is because in 99%
-//! of the cases, the runtime that is being tested is different from the one that is stored in the
-//! canonical chain state. This implies:
-//!
-//! 1. the state root will NEVER match, because `:CODE:` is different between the two.
-//! 2. replaying all transactions will fail, because the spec-version is part of the transaction
-//!    signature.
-//!
-//! ## Best Practices
-//!
-//! Try-runtime is all about battle-testing unreleased runtime. The following list of suggestions
-//! help developers maximize the testing coverage and make base use of `try-runtime`.
-//!
-//! #### Adding pre/post hooks
-//!
-//! One of the gems that come only in the `try-runtime` feature flag is the `pre_upgrade` and
-//! `post_upgrade` hooks for `OnRuntimeUpgrade`. This trait is implemented either inside the pallet,
-//! or manually in a runtime, to define a migration. In both cases, these functions can be added,
-//! given the right flag:
-//!
-//! ```ignore
-//! #[cfg(feature = "try-runtime")]
-//! fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {}
-//!
-//! #[cfg(feature = "try-runtime")]
-//! fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {}
-//! ```
-//!
-//! (The pallet macro syntax will support this simply as a part of `#[pallet::hooks]`).
-//!
-//! These hooks allow you to execute some code, only within the `on-runtime-upgrade` command, before
-//! and after the migration. Moreover, `pre_upgrade` can return a `Vec<u8>` that contains arbitrary
-//! encoded data (usually some pre-upgrade state) which will be passed to `post_upgrade` after
-//! upgrading and used for post checking.
-//!
-//! ## State Consistency
-//!
-//! Similarly, each pallet can expose a function in `#[pallet::hooks]` section as follows:
-//!
-//! ```ignore
-//! #[cfg(feature = "try-runtime")]
-//! fn try_state(_: BlockNumber) -> Result<(), TryRuntimeError> {}
-//! ```
-//!
-//! which is called on numerous code paths in the try-runtime tool. These checks should ensure that
-//! the state of the pallet is consistent and correct. See `frame_support::try_runtime::TryState`
-//! for more info.
-//!
-//! #### Logging
-//!
-//! It is super helpful to make sure your migration code uses logging (always with a `runtime` log
-//! target prefix, e.g. `runtime::balance`) and state exactly at which stage it is, and what it is
-//! doing.
-//!
-//! #### Guarding migrations
-//!
-//! Always make sure that any migration code is guarded either by `StorageVersion`, or by some
-//! custom storage item, so that it is NEVER executed twice, even if the code lives in two
-//! consecutive runtimes.
-//!
-//! ## Examples
-//!
-//! For the following examples, we assume the existence of the following:
-//!
-//! 1. a substrate node compiled without `--feature try-runtime`, called `substrate`. This will be
-//! the running node that you connect to. then, after some changes to this node, you compile it with
-//! `--features try-runtime`. This gives you:
-//! 2. a substrate binary that has the try-runtime sub-command enabled.
-//! 3. a wasm blob that has try-runtime functionality.
-//!
-//! ```bash
-//! # this is like your running deployed node.
-//! cargo build --release && cp target/release/substrate .
-//!
-//! # this is like your WIP branch.
-//! cargo build --release --features try-runtime
-//! cp target/release/substrate substrate-try-runtime
-//! cp ./target/release/wbuild/kitchensink-runtime/kitchensink_runtime.wasm runtime-try-runtime.wasm
-//! ```
-//!
-//! > The above example is with `substrate`'s `kitchensink-runtime`, but is applicable to any
-//! > substrate-based chain that has implemented `try-runtime-cli`.
-//!
-//! * If you run `try-runtime` subcommand against `substrate` binary listed above, you get the
-//!   following error.
-//!
-//! ```bash
-//! [substrate] ./substrate try-runtime
-//! Error: Input("TryRuntime wasn't enabled when building the node. You can enable it with `--features try-runtime`.")
-//! ```
-//!
-//! * If you run the same against `substrate-try-runtime`, it will work.
-//!
-//! ```bash
-//! [substrate] ./substrate-try-runtime try-runtime
-//! Try some command against runtime state
-//!
-//! Usage: substrate-try-runtime try-runtime [OPTIONS] --runtime <RUNTIME> <COMMAND>
-//!
-//! Commands:
-//!   on-runtime-upgrade  Execute the migrations of the "local runtime"
-//!   execute-block       Executes the given block against some state
-//!   offchain-worker     Executes *the offchain worker hooks* of a given block against some state
-//!   follow-chain        Follow the given chain's finalized blocks and apply all of its extrinsics
-//!   create-snapshot     Create a new snapshot file
-//!   help                Print this message or the help of the given subcommand(s)
-//!
-//! Options:
-//!       --chain <CHAIN_SPEC>
-//!           Specify the chain specification
-//!       --dev
-//!           Specify the development chain
-//!   -d, --base-path <PATH>
-//!           Specify custom base path
-//!   -l, --log <LOG_PATTERN>...
-//!           Sets a custom logging filter. Syntax is `<target>=<level>`, e.g. -lsync=debug
-//!       --detailed-log-output
-//!           Enable detailed log output
-//!       --disable-log-color
-//!           Disable log color output
-//!       --enable-log-reloading
-//!           Enable feature to dynamically update and reload the log filter
-//!       --tracing-targets <TARGETS>
-//!           Sets a custom profiling filter. Syntax is the same as for logging: `<target>=<level>`
-//!       --tracing-receiver <RECEIVER>
-//!           Receiver to process tracing messages [default: log] [possible values: log]
-//!       --runtime <RUNTIME>
-//!           The runtime to use
-//!       --wasm-execution <METHOD>
-//!           Type of wasm execution used [default: compiled] [possible values: interpreted-i-know-what-i-do, compiled]
-//!       --wasm-instantiation-strategy <STRATEGY>
-//!           The WASM instantiation method to use [default: pooling-copy-on-write] [possible values: pooling-copy-on-write, recreate-instance-copy-on-write, pooling, recreate-instance, legacy-instance-reuse]
-//!       --heap-pages <HEAP_PAGES>
-//!           The number of 64KB pages to allocate for Wasm execution. Defaults to [`sc_service::Configuration.default_heap_pages`]
-//!       --overwrite-state-version <OVERWRITE_STATE_VERSION>
-//!           Overwrite the `state_version`
-//!   -h, --help
-//!           Print help information (use `--help` for more detail)
-//!   -V, --version
-//!           Print version information
-//! ```
-//!
-//! * Run the migrations of a given runtime on top of a live state.
-//!
-//! ```bash
-//! # assuming there's `./substrate --dev --tmp --ws-port 9999` or similar running.
-//! ./substrate-try-runtime \
-//!     try-runtime \
-//!     --runtime runtime-try-runtime.wasm \
-//!     -lruntime=debug \
-//!     on-runtime-upgrade \
-//!     live --uri ws://localhost:9999
-//! ```
-//!
-//! * Same as the previous one, but run it at specific block number's state. This means that this
-//! block hash's state shall not yet have been pruned in `rpc.polkadot.io`.
-//!
-//! ```bash
-//! ./substrate-try-runtime \
-//!     try-runtime \
-//!     --runtime runtime-try-runtime.wasm \
-//!     -lruntime=debug \
-//!     on-runtime-upgrade \
-//!     live --uri ws://localhost:9999 \
-//!     # replace with your desired block hash!
-//!     --at 0xa1b16c1efd889a9f17375ec4dd5c1b4351a2be17fa069564fced10d23b9b3836
-//! ```
-//!
-//! * Executing the same command with the [`Runtime::Existing`] will fail because the existing
-//!   runtime, stored onchain in `substrate` binary that we compiled earlier does not have
-//!   `try-runtime` feature!
-//!
-//! ```bash
-//! ./substrate-try-runtime try-runtime --runtime existing -lruntime=debug on-runtime-upgrade live --uri ws://localhost:9999
-//! ...
-//! Error: Input("given runtime is NOT compiled with try-runtime feature!")
-//! ```
-//!
-//! * Now, let's use a snapshot file. First, we create the snapshot:
-//!
-//! ```bash
-//! ./substrate-try-runtime try-runtime --runtime existing -lruntime=debug create-snapshot --uri ws://localhost:9999
-//! 2022-12-13 10:28:17.516  INFO main try-runtime::cli: snapshot path not provided (-s), using 'node-268@latest.snap'
-//! 2022-12-13 10:28:17.516  INFO                 main remote-ext: since no at is provided, setting it to latest finalized head, 0xe7d0b614dfe89af65b33577aae46a6f958c974bf52f8a5e865a0f4faeb578d22
-//! 2022-12-13 10:28:17.516  INFO                 main remote-ext: since no prefix is filtered, the data for all pallets will be downloaded
-//! 2022-12-13 10:28:17.550  INFO                 main remote-ext: writing snapshot of 1611464 bytes to "node-268@latest.snap"
-//! 2022-12-13 10:28:17.551  INFO                 main remote-ext: initialized state externalities with storage root 0x925e4e95de4c08474fb7f976c4472fa9b8a1091619cd7820a793bf796ee6d932 and state_version V1
-//! ```
-//!
-//! > Note that the snapshot contains the `existing` runtime, which does not have the correct
-//! > `try-runtime` feature. In the following commands, we still need to overwrite the runtime.
-//!
-//! Then, we can use it to have the same command as before, `on-runtime-upgrade`
-//!
-//! ```bash
-//! ./substrate-try-runtime try-runtime \
-//!     --runtime runtime-try-runtime.wasm \
-//!     -lruntime=debug \
-//!     on-runtime-upgrade \
-//!     snap -s node-268@latest.snap
-//! ```
-//!
-//! * Execute the latest finalized block with the given runtime.
-//!
-//! ```bash
-//! ./substrate-try-runtime try-runtime \
-//!     --runtime runtime-try-runtime.wasm \
-//!     -lruntime=debug \
-//!     execute-block live \
-//!     --uri ws://localhost:9999
-//! ```
-//!
-//! This can still be customized at a given block with `--at`. If you want to use a snapshot, you
-//! can still use `--block-ws-uri` to provide a node form which the block data can be fetched.
-//!
-//! Moreover, this runs the `frame_support::try_runtime::TryState` hooks as well. The hooks to run
-//! can be customized with the `--try-state`. For example:
-//!
-//! ```bash
-//! ./substrate-try-runtime try-runtime \
-//!    --runtime runtime-try-runtime.wasm \
-//!    -lruntime=debug \
-//!    execute-block \
-//!    --try-state System,Staking \
-//!    live \
-//!    --uri ws://localhost:9999 \
-//!    --pallet System Staking
-//! ```
-//!
-//! Will only run the `try-state` of the two given pallets. When running `try-state` against
-//! some real chain data it can take a long time for the command to execute since it has to
-//! query all the key-value pairs. In scenarios like above where we only want to run the
-//! `try-state` for some specific pallets, we can use the `--pallet` option to specify from
-//! which pallets we want to query the state. This will greatly decrease the execution time.
-//!
-//! See [`frame_try_runtime::TryStateSelect`] for more information.
-//!
-//! * Follow our live chain's blocks using `follow-chain`, whilst running the try-state of 3 pallets
-//!   in a round robin fashion
-//!
-//! ```bash
-//! ./substrate-try-runtime \
-//!     try-runtime \
-//!     --runtime runtime-try-runtime.wasm \
-//!     -lruntime=debug \
-//!     follow-chain \
-//!     --uri ws://localhost:9999 \
-//!     --try-state rr-3
-//! ```
+//! It is no longer maintained here and will be removed in the future.
 
 #![cfg(feature = "try-runtime")]
 
@@ -722,7 +394,13 @@ impl State {
 	}
 }
 
+pub const DEPRECATION_NOTICE: &str = "Substrate's `try-runtime` subcommand has been migrated to a standalone CLI (https://github.com/paritytech/try-runtime-cli). It is no longer being maintained here and will be removed entirely some time after January 2024. Please remove this subcommand from your runtime and use the standalone CLI.";
+
 impl TryRuntimeCmd {
+	// Can't reuse DEPRECATION_NOTICE in the deprecated macro
+	#[deprecated(
+		note = "Substrate's `try-runtime` subcommand has been migrated to a standalone CLI (https://github.com/paritytech/try-runtime-cli). It is no longer being maintained here and will be removed entirely some time after January 2024. Please remove this subcommand from your runtime and use the standalone CLI."
+	)]
 	pub async fn run<Block, HostFns, BBIP>(
 		&self,
 		block_building_info_provider: Option<BBIP>,
diff --git a/substrate/utils/frame/try-runtime/cli/tests/create_snapshot.rs b/substrate/utils/frame/try-runtime/cli/tests/create_snapshot.rs
deleted file mode 100644
index c524e5af48ad3992d1611cc839c020d472a81b9d..0000000000000000000000000000000000000000
--- a/substrate/utils/frame/try-runtime/cli/tests/create_snapshot.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-#![cfg(unix)]
-#![cfg(feature = "try-runtime")]
-
-use assert_cmd::cargo::cargo_bin;
-use node_primitives::Hash;
-use regex::Regex;
-use remote_externalities::{Builder, Mode, OfflineConfig, SnapshotConfig};
-use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper};
-use std::{
-	path::{Path, PathBuf},
-	process,
-	time::Duration,
-};
-use substrate_cli_test_utils as common;
-use tokio::process::{Child, Command};
-
-type Block = RawBlock<ExtrinsicWrapper<Hash>>;
-
-#[tokio::test]
-async fn create_snapshot_works() {
-	// Build substrate so binaries used in the test use the latest code.
-	common::build_substrate(&["--features=try-runtime"]);
-
-	let temp_dir = tempfile::Builder::new()
-		.prefix("try-runtime-cli-test-dir")
-		.tempdir()
-		.expect("Failed to create a tempdir");
-	let snap_file_path = temp_dir.path().join("snapshot.snap");
-
-	common::run_with_timeout(Duration::from_secs(60), async move {
-		fn create_snapshot(ws_url: &str, snap_file: &PathBuf, at: Hash) -> Child {
-			Command::new(cargo_bin("substrate-node"))
-				.stdout(process::Stdio::piped())
-				.stderr(process::Stdio::piped())
-				.args(&["try-runtime", "--runtime=existing"])
-				.args(&["create-snapshot", format!("--uri={}", ws_url).as_str()])
-				.arg(snap_file)
-				.args(&["--at", format!("{:?}", at).as_str()])
-				.kill_on_drop(true)
-				.spawn()
-				.unwrap()
-		}
-
-		// Start a node and wait for it to begin finalizing blocks
-		let mut node = common::KillChildOnDrop(common::start_node());
-		let ws_url = common::extract_info_from_output(node.stderr.take().unwrap()).0.ws_url;
-		common::wait_n_finalized_blocks(3, &ws_url).await;
-
-		let block_number = 2;
-		let block_hash = common::block_hash(block_number, &ws_url).await.unwrap();
-
-		// Try to create a snapshot.
-		let mut snapshot_creation = create_snapshot(&ws_url, &snap_file_path, block_hash);
-
-		let re = Regex::new(r#".*writing snapshot of (\d+) bytes to .*"#).unwrap();
-		let matched =
-			common::wait_for_stream_pattern_match(snapshot_creation.stderr.take().unwrap(), re)
-				.await;
-
-		// Assert that the snapshot creation succeded.
-		assert!(matched.is_ok(), "Failed to create snapshot");
-
-		let snapshot_is_on_disk = Path::new(&snap_file_path).exists();
-		assert!(snapshot_is_on_disk, "Snapshot was not written to disk");
-
-		// Try and load the snapshot we have created by running `create-snapshot`.
-		let snapshot_loading_result = Builder::<Block>::new()
-			.mode(Mode::Offline(OfflineConfig {
-				state_snapshot: SnapshotConfig { path: snap_file_path },
-			}))
-			.build()
-			.await;
-
-		assert!(snapshot_loading_result.is_ok(), "Snapshot couldn't be loaded");
-	})
-	.await;
-}
diff --git a/substrate/utils/frame/try-runtime/cli/tests/execute_block.rs b/substrate/utils/frame/try-runtime/cli/tests/execute_block.rs
deleted file mode 100644
index 9ad49e0ceaf9aa29a41ce190a2b7b2060f2d05e8..0000000000000000000000000000000000000000
--- a/substrate/utils/frame/try-runtime/cli/tests/execute_block.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-#![cfg(unix)]
-#![cfg(feature = "try-runtime")]
-
-use assert_cmd::cargo::cargo_bin;
-use node_primitives::Hash;
-use regex::Regex;
-use std::{process, time::Duration};
-use substrate_cli_test_utils as common;
-use tokio::process::{Child, Command};
-
-#[tokio::test]
-async fn block_execution_works() {
-	// Build substrate so binaries used in the test use the latest code.
-	common::build_substrate(&["--features=try-runtime"]);
-
-	common::run_with_timeout(Duration::from_secs(60), async move {
-		fn execute_block(ws_url: &str, at: Hash) -> Child {
-			Command::new(cargo_bin("substrate-node"))
-				.stdout(process::Stdio::piped())
-				.stderr(process::Stdio::piped())
-				.args(&["try-runtime", "--runtime=existing"])
-				.args(&["execute-block"])
-				.args(&["live", format!("--uri={}", ws_url).as_str()])
-				.args(&["--at", format!("{:?}", at).as_str()])
-				.kill_on_drop(true)
-				.spawn()
-				.unwrap()
-		}
-
-		// Start a node and wait for it to begin finalizing blocks
-		let mut node = common::KillChildOnDrop(common::start_node());
-		let ws_url = common::extract_info_from_output(node.stderr.take().unwrap()).0.ws_url;
-		common::wait_n_finalized_blocks(3, &ws_url).await;
-
-		let block_number = 1;
-		let block_hash = common::block_hash(block_number, &ws_url).await.unwrap();
-
-		// Try to execute the block.
-		let mut block_execution = execute_block(&ws_url, block_hash);
-
-		// The execute-block command is actually executing the next block.
-		let expected_output =
-			format!(r#".*Block #{} successfully executed"#, block_number.saturating_add(1));
-		let re = Regex::new(expected_output.as_str()).unwrap();
-		let matched =
-			common::wait_for_stream_pattern_match(block_execution.stderr.take().unwrap(), re).await;
-
-		// Assert that the block-execution process has executed a block.
-		assert!(matched.is_ok());
-	})
-	.await;
-}
diff --git a/substrate/utils/frame/try-runtime/cli/tests/follow_chain.rs b/substrate/utils/frame/try-runtime/cli/tests/follow_chain.rs
deleted file mode 100644
index d7ff7b09cbb721b97106b91484e76864761082b2..0000000000000000000000000000000000000000
--- a/substrate/utils/frame/try-runtime/cli/tests/follow_chain.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-#![cfg(unix)]
-#![cfg(feature = "try-runtime")]
-
-use assert_cmd::cargo::cargo_bin;
-use regex::Regex;
-use std::{
-	process::{self},
-	time::Duration,
-};
-use substrate_cli_test_utils as common;
-use tokio::process::{Child, Command};
-
-#[tokio::test]
-async fn follow_chain_works() {
-	// Build substrate so binaries used in the test use the latest code.
-	common::build_substrate(&["--features=try-runtime"]);
-
-	common::run_with_timeout(Duration::from_secs(60), async move {
-		fn start_follow(ws_url: &str) -> Child {
-			Command::new(cargo_bin("substrate-node"))
-				.stdout(process::Stdio::piped())
-				.stderr(process::Stdio::piped())
-				.args(&["try-runtime", "--runtime=existing"])
-				.args(&["follow-chain", format!("--uri={}", ws_url).as_str()])
-				.kill_on_drop(true)
-				.spawn()
-				.unwrap()
-		}
-
-		// Start a node and wait for it to begin finalizing blocks
-		let mut node = common::KillChildOnDrop(common::start_node());
-		let ws_url = common::extract_info_from_output(node.stderr.take().unwrap()).0.ws_url;
-		common::wait_n_finalized_blocks(1, &ws_url).await;
-
-		// Kick off the follow-chain process and wait for it to process at least 3 blocks.
-		let mut follow = start_follow(&ws_url);
-		let re = Regex::new(r#".*executed block ([3-9]|[1-9]\d+).*"#).unwrap();
-		let matched =
-			common::wait_for_stream_pattern_match(follow.stderr.take().unwrap(), re).await;
-
-		// Assert that the follow-chain process has followed at least 3 blocks.
-		assert!(matched.is_ok());
-	})
-	.await;
-}