diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
index 385717608c7a052554dc3be378b134756b48ea79..475a60e95e29a40d0a91ce80fa069c48a5d20bef 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
@@ -196,6 +196,7 @@ import org.whispersystems.textsecuregcm.websocket.DeadLetterHandler;
 import org.whispersystems.textsecuregcm.websocket.ProvisioningConnectListener;
 import org.whispersystems.textsecuregcm.websocket.WebSocketAccountAuthenticator;
 import org.whispersystems.textsecuregcm.workers.CertificateCommand;
+import org.whispersystems.textsecuregcm.workers.CheckDynamicConfigurationCommand;
 import org.whispersystems.textsecuregcm.workers.DeleteUserCommand;
 import org.whispersystems.textsecuregcm.workers.GetRedisCommandStatsCommand;
 import org.whispersystems.textsecuregcm.workers.GetRedisSlowlogCommand;
@@ -226,6 +227,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
     bootstrap.addCommand(new GetRedisSlowlogCommand());
     bootstrap.addCommand(new GetRedisCommandStatsCommand());
     bootstrap.addCommand(new ServerVersionCommand());
+    bootstrap.addCommand(new CheckDynamicConfigurationCommand());
 
     bootstrap.addBundle(new NameableMigrationsBundle<WhisperServerConfiguration>("accountdb", "accountsdb.xml") {
       @Override
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/workers/CheckDynamicConfigurationCommand.java b/service/src/main/java/org/whispersystems/textsecuregcm/workers/CheckDynamicConfigurationCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ce1047566fd22839f85d043bb052a97dc787f65
--- /dev/null
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/workers/CheckDynamicConfigurationCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013-2021 Signal Messenger, LLC
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+package org.whispersystems.textsecuregcm.workers;
+
+import io.dropwizard.cli.Command;
+import io.dropwizard.setup.Bootstrap;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
+import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
+
+public class CheckDynamicConfigurationCommand extends Command {
+
+  public CheckDynamicConfigurationCommand() {
+    super("check-dynamic-config", "Check validity of a dynamic configuration file");
+  }
+
+  @Override
+  public void configure(final Subparser subparser) {
+    subparser.addArgument("file")
+        .type(String.class)
+        .required(true)
+        .help("Dynamic configuration file to check");
+  }
+
+  @Override
+  public void run(final Bootstrap<?> bootstrap, final Namespace namespace) throws Exception {
+    final Path path = Path.of(namespace.getString("file"));
+
+    if (DynamicConfigurationManager.parseConfiguration(Files.readString(path)).isPresent()) {
+      System.out.println("Dynamic configuration file at " + path + " is valid");
+    } else {
+      System.err.println("Dynamic configuration file at " + path + " is not valid");
+    }
+  }
+}