diff --git a/objectstore/DriveRegister.cpp b/objectstore/DriveRegister.cpp
index 9d086f6e778fb358fa97d7412e63916485a5179d..89526e960a5b84d0fdc5057d6558030690e7243d 100644
--- a/objectstore/DriveRegister.cpp
+++ b/objectstore/DriveRegister.cpp
@@ -265,6 +265,24 @@ update:
   }
 }
 
+//------------------------------------------------------------------------------
+// DriveRegister::removeDrive())
+//------------------------------------------------------------------------------
+void DriveRegister::removeDrive(const std::string  & driveName) {
+  checkPayloadWritable();
+  auto driveToRemove = m_payload.mutable_drives()->begin();
+  while (driveToRemove != m_payload.mutable_drives()->end()) {
+    if ( driveToRemove->drivename() == driveName) {
+      m_payload.mutable_drives()->erase(driveToRemove);
+      return;
+    }
+    driveToRemove++;
+  }
+  std::stringstream err;
+  err << "In DriveRegister::removeDrive(): drive not found: " << driveName;
+  throw cta::exception::Exception(err.str()); 
+}
+
 //------------------------------------------------------------------------------
 // DriveRegister::isEmpty())
 //------------------------------------------------------------------------------
diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp
index b8a9a234a6e469fbf03aaa7ab980fff8a4b61863..a7befdd8e3a87e06ad328c54d9b246e3c90d5100 100644
--- a/scheduler/OStoreDB/OStoreDB.cpp
+++ b/scheduler/OStoreDB/OStoreDB.cpp
@@ -1056,6 +1056,20 @@ void OStoreDB::setDesiredDriveState(const std::string& drive, const common::data
   dr.commit();
 }
 
+//------------------------------------------------------------------------------
+// OStoreDB::removeDrive()
+//------------------------------------------------------------------------------
+void OStoreDB::removeDrive(const std::string& drive) {
+  RootEntry re(m_objectStore);
+  re.fetchNoLock();
+  auto driveRegisterAddress = re.getDriveRegisterAddress();
+  objectstore::DriveRegister dr(driveRegisterAddress, m_objectStore);
+  objectstore::ScopedExclusiveLock drl(dr);
+  dr.fetch();
+  dr.removeDrive(drive);
+  dr.commit();
+}
+ 
 //------------------------------------------------------------------------------
 // OStoreDB::reportDriveStatus()
 //------------------------------------------------------------------------------
diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp
index 46bce86c527ad588c0f5f78be65f4d965da14c1e..9eb820dc707f850aa0c22aa5f65a380312981d6a 100644
--- a/scheduler/OStoreDB/OStoreDB.hpp
+++ b/scheduler/OStoreDB/OStoreDB.hpp
@@ -270,6 +270,8 @@ public:
   std::list<cta::common::dataStructures::DriveState> getDriveStates() const override;
   
   void setDesiredDriveState(const std::string& drive, const common::dataStructures::DesiredDriveState & desiredState) override;
+    
+  void removeDrive(const std::string & drive) override;
   
   void reportDriveStatus(const common::dataStructures::DriveInfo& driveInfo, cta::common::dataStructures::MountType mountType, 
     common::dataStructures::DriveStatus status, time_t reportTime, uint64_t mountSessionId, uint64_t byteTransfered, 
diff --git a/scheduler/OStoreDB/OStoreDBFactory.hpp b/scheduler/OStoreDB/OStoreDBFactory.hpp
index e4c5ee9e98f27b78362f1e0ec4cb397595c7fbe8..8c10b2294340059ef24ca345363b9dd74595adb7 100644
--- a/scheduler/OStoreDB/OStoreDBFactory.hpp
+++ b/scheduler/OStoreDB/OStoreDBFactory.hpp
@@ -152,6 +152,10 @@ public:
     return m_OStoreDB.setDesiredDriveState(drive, desiredState);
   }
   
+  void removeDrive(const std::string & drive) override {
+    return m_OStoreDB.removeDrive(drive);
+  }
+  
   void reportDriveStatus(const common::dataStructures::DriveInfo& driveInfo, cta::common::dataStructures::MountType mountType, 
     common::dataStructures::DriveStatus status, time_t reportTime, uint64_t mountSessionId, uint64_t byteTransfered, 
     uint64_t filesTransfered, double latestBandwidth, const std::string& vid, const std::string& tapepool) override {
diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp
index 6623adec25e57f356170957ca0351df79d7019d4..d8bac3f0abe16a8b5eea1a9c8b3212692f4fd0be 100644
--- a/scheduler/Scheduler.cpp
+++ b/scheduler/Scheduler.cpp
@@ -371,6 +371,20 @@ void Scheduler::setDesiredDriveState(const common::dataStructures::SecurityIdent
    lc.log(log::INFO, "In Scheduler::setDesiredDriveState(): success.");   
 }
 
+//------------------------------------------------------------------------------
+// removeDrive
+//------------------------------------------------------------------------------
+void Scheduler::removeDrive(const common::dataStructures::SecurityIdentity &cliIdentity, 
+  const std::string &driveName, log::LogContext & lc) {
+  utils::Timer t;
+  m_db.removeDrive(driveName);
+  auto schedulerDbTime = t.secs();
+  log::ScopedParamContainer spc(lc);
+  spc.add("drive", driveName)
+     .add("schedulerDbTime", schedulerDbTime);
+  lc.log(log::INFO, "In Scheduler::removeDrive(): success.");   
+}
+
 //------------------------------------------------------------------------------
 // setDesiredDriveState
 //------------------------------------------------------------------------------
diff --git a/scheduler/Scheduler.hpp b/scheduler/Scheduler.hpp
index 49a9f93ee29cce89fd462bc83feb474400cca052..db4fa6f16dddd8c08dfbc0dcacd1b5301b4a05e9 100644
--- a/scheduler/Scheduler.hpp
+++ b/scheduler/Scheduler.hpp
@@ -216,6 +216,15 @@ public:
   void setDesiredDriveState(const cta::common::dataStructures::SecurityIdentity &cliIdentity,
     const std::string &driveName, const bool up, const bool force, log::LogContext & lc);
   
+  /**
+   * Remove drive from the drive register.
+   * 
+   * @param cliIdentity The identity of the user requesting the drive removal.
+   * @param driveName The drive name
+   */
+  void removeDrive(const cta::common::dataStructures::SecurityIdentity &cliIdentity,
+    const std::string &driveName, log::LogContext & lc);
+  
   /**
    * Reports the state of the drive to the object store. This information is then reported
    * to the user through the command line interface, via getDriveStates(). This function
diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp
index ed15f63eb2d551e8d6abc22d44605f7da1b2e3d7..f6c8914285ec1761894eac0785611dc3b71482b7 100644
--- a/scheduler/SchedulerDatabase.hpp
+++ b/scheduler/SchedulerDatabase.hpp
@@ -478,6 +478,14 @@ public:
    */
   virtual void setDesiredDriveState(const std::string & drive, const cta::common::dataStructures::DesiredDriveState & state) = 0;
   
+  /**
+   * Remove drive from the drive register.
+   * Will throw an exception is the drive does not exist.
+   * 
+   * @param drive The drive name.
+   */
+  virtual void removeDrive(const std::string & drive) = 0;
+  
   /**
    * Sets the drive status in the object store. The drive status will be recorded in all cases,
    * although some historical information is needed to provide an accurate view of the
diff --git a/xroot_plugins/XrdCtaFile.cpp b/xroot_plugins/XrdCtaFile.cpp
index 6d225af666835bcacc894ef760895ad315b72de0..e185bfc457d3ce68fd5536f78c891e17d9d81782 100644
--- a/xroot_plugins/XrdCtaFile.cpp
+++ b/xroot_plugins/XrdCtaFile.cpp
@@ -1835,14 +1835,18 @@ std::string XrdCtaFile::xCom_drive() {
   log::LogContext lc(m_log);
   std::stringstream cmdlineOutput;
   std::stringstream help;
-  help << m_requestTokens.at(0) << " dr/drive up/down/ls (it is a synchronous command):"    << std::endl
+  help << m_requestTokens.at(0) << " dr/drive up/down/ls/rm (it is a synchronous command):"    << std::endl
        << "Set the requested state of the drives. The drives will complete any running mount" << std::endl
        << "unless it is preempted with the --force option."                                 << std::endl
        << "\tup <drives_name>"                                                               << std::endl
        << "\tdown <drives_name> [--force/-f]"                                                << std::endl
        << ""                                                                                << std::endl
-       << "List the states for one or all drives"                                           << std::endl
-       << "\tls [<drive_name>]"                                                             << std::endl;
+       << "List the states for one or all drives."                                          << std::endl
+       << "\tls [<drive_name>]"                                                             << std::endl
+       << ""                                                                                << std::endl
+       << "Remove drive or drives by regex. The drives must be in state Down"
+          " unless --force option is set."                                                   << std::endl
+       << "\trm <drive_name> [--force/-f]"                                                  << std::endl;
        
   if (hasOption("-?", "--help")) {
     return help.str();
@@ -1871,6 +1875,22 @@ std::string XrdCtaFile::xCom_drive() {
     // Check if the force option was present.
     bool force=reply.options.size() && (reply.options.at(0).option == "f");
     changeStateForDrivesByRegex(m_requestTokens.at(3), lc, cmdlineOutput, false, force);
+  } else if ("rm" == m_requestTokens.at(2)) {
+    // Parse the command line for option and drive name.
+    cta::utils::GetOpThreadSafe::Request req;
+    for (size_t i=2; i<m_requestTokens.size(); i++)
+      req.argv.push_back(m_requestTokens.at(i));
+    req.optstring = { "f" };
+    struct ::option longOptions[] = { { "force", no_argument, 0 , 'f' }, { 0, 0, 0, 0 } };
+    req.longopts = longOptions;
+    auto reply = cta::utils::GetOpThreadSafe::getOpt(req);
+    // We should have one and only one no-option argument, the drive name.
+    if (reply.remainder.size() != 1) {
+      throw cta::exception::UserError(help.str());
+    }
+    // Check if the force option was present.
+    bool force=reply.options.size() && (reply.options.at(0).option == "f");
+    removeDrivesByRegex(m_requestTokens.at(3), lc, cmdlineOutput, force);
   } else if ("ls" == m_requestTokens.at(2)) {
     if ((m_requestTokens.size() == 3) || (m_requestTokens.size() == 4)) {
       // We will dump all the drives, and select the one asked for if needed.
@@ -1994,6 +2014,41 @@ void XrdCtaFile::changeStateForDrivesByRegex(const std::string &regex,
     }
 }
 
+//------------------------------------------------------------------------------
+// removeDrivesByRegex
+//------------------------------------------------------------------------------
+void XrdCtaFile::removeDrivesByRegex(const std::string &regex,
+  log::LogContext &lc, std::stringstream &cmdlineOutput,
+  const bool isForceSet) {
+  cta::utils::Regex driveNameRegex(regex.c_str());
+    auto driveStates = m_scheduler->getDriveStates(m_cliIdentity, lc);
+    bool drivesNotFound = true;
+    for (auto driveState: driveStates) {
+      const auto regexResult = driveNameRegex.exec(driveState.driveName);
+      if (regexResult.size()) {
+        const std::set<int> downDriveStatuses = {
+          (int)cta::common::dataStructures::DriveStatus::Down,
+          (int)cta::common::dataStructures::DriveStatus::Shutdown,
+          (int)cta::common::dataStructures::DriveStatus::Unknown};  
+        if (downDriveStatuses.count((int)driveState.driveStatus)
+            || isForceSet ) {  
+            m_scheduler->removeDrive(m_cliIdentity, driveState.driveName, lc);
+            cmdlineOutput << "Drive " << driveState.driveName << " removed"
+                          << (isForceSet?" (forced)":"")
+                          << "." << std::endl;            
+        } else {
+          cmdlineOutput << "Drive " << driveState.driveName << " in state "
+                        << cta::common::dataStructures::toString(driveState.driveStatus)
+                        << " and force is not set (skipped)." << std::endl;
+        }
+        drivesNotFound = false;
+      }
+    }
+    if (drivesNotFound) {
+      cmdlineOutput << "Drives not found by regex: " << regex << std::endl;
+    }
+}
+
 //------------------------------------------------------------------------------
 // xCom_listpendingarchives
 //------------------------------------------------------------------------------
diff --git a/xroot_plugins/XrdCtaFile.hpp b/xroot_plugins/XrdCtaFile.hpp
index 4b843874c1970127cd90002cf3afc8e616712632..c93a1ec6fb960a7e86f4094631f4adfaa960822c 100644
--- a/xroot_plugins/XrdCtaFile.hpp
+++ b/xroot_plugins/XrdCtaFile.hpp
@@ -375,6 +375,20 @@ protected:
   void changeStateForDrivesByRegex(const std::string &regex,
     log::LogContext &lc, std::stringstream &cmdlineOutput, const bool isMakeUp,
     const bool isForceSet);
+  
+  /**
+   * Remove drives from the drive register by a given regex. By default drive
+   * should be in state Down to be removed. If a force flag is set then drive
+   * will be removed with any state.
+   *
+   * @param regex The regex to be used to match drive name.
+   * @param lc    The log context.
+   * @param cmdlineOutput The string stream to stream output.
+   * @param isForceSet The boolean value for force parameter.
+   */
+  void removeDrivesByRegex(const std::string &regex,
+    log::LogContext &lc, std::stringstream &cmdlineOutput,
+    const bool isForceSet);
 
   /**
    * Returns the response string properly formatted in a table