diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,8 @@
 # Revision history for haskell-amqp-utils
 
+## 0.4.0.1  -- 2019-12-04
+* fix exit codes
+
 ## 0.4.0.0  -- 2019-11-11
 * agitprop: show exchange arg
 * agitprop does not need -q or -Q
diff --git a/agitprop.hs b/agitprop.hs
--- a/agitprop.hs
+++ b/agitprop.hs
@@ -22,6 +22,7 @@
 import Network.AMQP.Utils.Options
 import Paths_amqp_utils (version)
 import System.Environment
+import System.Exit
 import System.INotify
 import qualified System.Posix.Files as F
 
@@ -81,13 +82,18 @@
            then mapM_ (publishOneMsg Nothing) (BL.lines messageFile)
            else publishOneMsg (Just (inputFile args)) messageFile
          hr "END sending")
-    (\exception -> printparam' "exception" $ show (exception :: X.SomeException))
+    exceptionHandler
   -- all done. wait and close.
   if (confirm args)
     then waitForConfirms chan >>= (printparam' "confirmed") . show
     else return ()
-  closeConnection conn
-  hr "connection closed"
+  X.catch (closeConnection conn) exceptionHandler
+
+-- | A handler for clean exit
+exceptionHandler :: AMQPException -> IO ()
+exceptionHandler (ChannelClosedException Normal txt) = printparam' "exit" txt >> exitWith ExitSuccess
+exceptionHandler (ConnectionClosedException Normal txt) = printparam' "exit" txt >> exitWith ExitSuccess
+exceptionHandler x = printparam' "exception" (show x) >> exitWith (ExitFailure 1)
 
 -- | The handler for publisher confirms
 confirmCallback :: (Word64, Bool, AckType) -> IO ()
diff --git a/amqp-utils.cabal b/amqp-utils.cabal
--- a/amqp-utils.cabal
+++ b/amqp-utils.cabal
@@ -1,6 +1,6 @@
 name:                amqp-utils
 
-version:             0.4.0.0
+version:             0.4.0.1
 
 synopsis:            Generic Haskell AMQP tools
 
