diff --git a/Ganeti/HTools/CLI.hs b/Ganeti/HTools/CLI.hs
index b977b6a854573f0bae6ff242f758779b63ccb176..696333aed6d001e13ce19ffd24f1f27e04574b81 100644
--- a/Ganeti/HTools/CLI.hs
+++ b/Ganeti/HTools/CLI.hs
@@ -59,6 +59,7 @@ module Ganeti.HTools.CLI
     , oDiskMoves
     , oDynuFile
     , oTieredSpec
+    , oExTags
     , oShowVer
     , oShowHelp
     ) where
@@ -106,6 +107,7 @@ data Options = Options
     , optMdsk        :: Double         -- ^ Max disk usage ratio for nodes
     , optDiskMoves   :: Bool           -- ^ Allow disk moves
     , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
+    , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
     , optVerbose     :: Int            -- ^ Verbosity level
     , optShowVer     :: Bool           -- ^ Just show the program version
     , optShowHelp    :: Bool           -- ^ Just show the help
@@ -138,6 +140,7 @@ defaultOptions  = Options
  , optMdsk        = -1
  , optDiskMoves   = True
  , optDynuFile    = Nothing
+ , optExTags      = Nothing
  , optVerbose     = 1
  , optShowVer     = False
  , optShowHelp    = False
@@ -293,6 +296,11 @@ oDynuFile = Option "U" ["dynu-file"]
             (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
             "Import dynamic utilisation data from the given FILE"
 
+oExTags :: OptType
+oExTags = Option "" ["exclusion-tags"]
+            (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
+             "TAG,...") "Enable instance exclusion based on given tag prefix"
+
 oTieredSpec :: OptType
 oTieredSpec = Option "" ["tiered-alloc"]
              (ReqArg (\ inp opts -> do
diff --git a/Ganeti/HTools/ExtLoader.hs b/Ganeti/HTools/ExtLoader.hs
index cc11b1c8bbda739ce7e0919fe0c7de68bdf6a67a..bd2e01ad57a99ac7d9c1c3d70580fdc1f40bf8d2 100644
--- a/Ganeti/HTools/ExtLoader.hs
+++ b/Ganeti/HTools/ExtLoader.hs
@@ -98,6 +98,10 @@ loadExternalData opts = do
       setSim = isJust simdata
       setFiles = optNodeSet opts || optInstSet opts
       allSet = filter id [setRapi, setLuxi, setFiles]
+      exTags = case optExTags opts of
+                 Nothing -> []
+                 Just etl -> map (++ ":") etl
+
   when (length allSet > 1) $
        do
          hPutStrLn stderr ("Error: Only one of the rapi, luxi, and data" ++
@@ -126,7 +130,7 @@ loadExternalData opts = do
           | setSim -> Simu.loadData $ fromJust simdata
           | otherwise -> wrapIO $ Text.loadData nodef instf
 
-  let ldresult = input_data >>= Loader.mergeData util_data'
+  let ldresult = input_data >>= Loader.mergeData util_data' exTags
   (loaded_nl, il, csf) <-
       (case ldresult of
          Ok x -> return x
diff --git a/Ganeti/HTools/IAlloc.hs b/Ganeti/HTools/IAlloc.hs
index b43939c8e13291405afb272e405628184ad48cf6..3215cb33cdce17f4019808c876bc011dfd05c4bd 100644
--- a/Ganeti/HTools/IAlloc.hs
+++ b/Ganeti/HTools/IAlloc.hs
@@ -110,7 +110,7 @@ parseData body = do
   iobj <- mapM (\(x,y) ->
                     asJSObject y >>= parseInstance ktn x . fromJSObject) idata
   let (kti, il) = assignIndices iobj
-  (map_n, map_i, csf) <- mergeData [] (nl, il)
+  (map_n, map_i, csf) <- mergeData [] [] (nl, il)
   req_nodes <- fromObj "required_nodes" request
   optype <- fromObj "type" request
   rqtype <-
diff --git a/Ganeti/HTools/Loader.hs b/Ganeti/HTools/Loader.hs
index 8a351502b5c0e95ee636eea9cae3dbf69ff3c5fd..35be6ffb3309138e2988060929b18726d4a5a8d3 100644
--- a/Ganeti/HTools/Loader.hs
+++ b/Ganeti/HTools/Loader.hs
@@ -114,6 +114,14 @@ fixNodes accu inst =
            in (sdx, snew):ac3
       else ac2
 
+-- | Remove non-selected tags from the exclusion list
+filterExTags :: [String] -> Instance.Instance -> Instance.Instance
+filterExTags tl inst =
+    let old_tags = Instance.tags inst
+        new_tags = filter (\tag -> any (\extag -> isPrefixOf extag tag) tl)
+                   old_tags
+    in inst { Instance.tags = new_tags }
+
 -- | Compute the longest common suffix of a list of strings that
 -- | starts with a dot.
 longestDomain :: [String] -> String
@@ -131,11 +139,12 @@ stripSuffix sflen name = take (length name - sflen) name
 -- | Initializer function that loads the data from a node and instance
 -- list and massages it into the correct format.
 mergeData :: [(String, DynUtil)]  -- ^ Instance utilisation data
+          -> [String]             -- ^ Exclusion tags
           -> (Node.AssocList,
               Instance.AssocList) -- ^ Data from either Text.loadData
                                   -- or Rapi.loadData
           -> Result (Node.List, Instance.List, String)
-mergeData um (nl, il) =
+mergeData um extags (nl, il) =
   let il2 = Container.fromAssocList il
       il3 = foldl' (\im (name, n_util) ->
                         case Container.findByName im name of
@@ -144,15 +153,16 @@ mergeData um (nl, il) =
                               let new_i = inst { Instance.util = n_util }
                               in Container.add (Instance.idx inst) new_i im
                    ) il2 um
-      nl2 = foldl' fixNodes nl (Container.elems il3)
+      il4 = Container.map (filterExTags extags) il3
+      nl2 = foldl' fixNodes nl (Container.elems il4)
       nl3 = Container.fromAssocList
-            (map (\ (k, v) -> (k, Node.buildPeers v il3)) nl2)
+            (map (\ (k, v) -> (k, Node.buildPeers v il4)) nl2)
       node_names = map (Node.name . snd) nl
       inst_names = map (Instance.name . snd) il
       common_suffix = longestDomain (node_names ++ inst_names)
       csl = length common_suffix
       snl = Container.map (\n -> setName n (stripSuffix csl $ nameOf n)) nl3
-      sil = Container.map (\i -> setName i (stripSuffix csl $ nameOf i)) il3
+      sil = Container.map (\i -> setName i (stripSuffix csl $ nameOf i)) il4
   in Ok (snl, sil, common_suffix)
 
 -- | Checks the cluster data for consistency.
diff --git a/hbal.hs b/hbal.hs
index 1ad686e89b24019bc59f070f75ac04ece5b56632..c2a58882b32a05b86ea4308356ba104522fe5882 100644
--- a/hbal.hs
+++ b/hbal.hs
@@ -73,6 +73,7 @@ options =
     , oMinDisk
     , oDiskMoves
     , oDynuFile
+    , oExTags
     , oShowVer
     , oShowHelp
     ]
diff --git a/hscan.hs b/hscan.hs
index 8b23793f1de773b6f32edf91695ebf019007b715..1d5ef9cb2a3fbf0980a8e5f30b9a3753fb81f741 100644
--- a/hscan.hs
+++ b/hscan.hs
@@ -137,7 +137,7 @@ main = do
               printf "%-*s " nlen name
               hFlush stdout
               input_data <- Rapi.loadData name
-              let ldresult = input_data >>= Loader.mergeData []
+              let ldresult = input_data >>= Loader.mergeData [] []
               (case ldresult of
                  Bad err -> printf "\nError: failed to load data. \
                                    \Details:\n%s\n" err