diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Change Log
 
+## 0.12.0 - 2019-12-02
+
+* Add support for EVENT_USER_BINARY_MSG ([#54](https://github.com/haskell/ghc-events/pull/54))
+
 ## 0.11.0 - 2019-10-29
 
 * Add support for time profiling events (ProfSampleCostCetre and ProfBegin) ([#53](https://github.com/haskell/ghc-events/pull/53))
diff --git a/ghc-events.cabal b/ghc-events.cabal
--- a/ghc-events.cabal
+++ b/ghc-events.cabal
@@ -1,5 +1,5 @@
 name:             ghc-events
-version:          0.11.0
+version:          0.12.0
 synopsis:         Library and tool for parsing .eventlog files from GHC
 description:      Parses .eventlog files emitted by GHC 6.12.1 and later.
                   Includes the ghc-events tool permitting, in particular,
@@ -63,6 +63,8 @@
                     test/biographical-samples.eventlog.reference
                     test/time-prof.eventlog
                     test/time-prof.eventlog.reference
+                    test/trace-binary-event.eventlog
+                    test/trace-binary-event.eventlog.reference
                     test/Utils.hs
                     test/stop.hs
                     README.md
diff --git a/include/EventLogFormat.h b/include/EventLogFormat.h
--- a/include/EventLogFormat.h
+++ b/include/EventLogFormat.h
@@ -200,12 +200,14 @@
 #define EVENT_PROF_SAMPLE_COST_CENTRE      167
 #define EVENT_PROF_BEGIN                   168
 
+#define EVENT_USER_BINARY_MSG              181
+
 /*
  * The highest event code +1 that ghc itself emits. Note that some event
  * ranges higher than this are reserved but not currently emitted by ghc.
  * This must match the size of the EventDesc[] array in EventLog.c
  */
-#define NUM_GHC_EVENT_TAGS        181
+#define NUM_GHC_EVENT_TAGS        182
 
 
 /* DEPRECATED EVENTS: */
diff --git a/src/GHC/RTS/EventTypes.hs b/src/GHC/RTS/EventTypes.hs
--- a/src/GHC/RTS/EventTypes.hs
+++ b/src/GHC/RTS/EventTypes.hs
@@ -5,6 +5,7 @@
 
 import Data.Binary
 import Data.Text (Text)
+import qualified Data.ByteString as B
 import qualified Data.Vector.Unboxed as VU
 
 -- EventType.
@@ -427,6 +428,9 @@
                        }
   | ProfBegin
                        { profTickInterval :: !Word64
+                       }
+
+  | UserBinaryMessage  { payload :: !B.ByteString
                        }
   deriving Show
 
diff --git a/src/GHC/RTS/Events.hs b/src/GHC/RTS/Events.hs
--- a/src/GHC/RTS/Events.hs
+++ b/src/GHC/RTS/Events.hs
@@ -73,13 +73,16 @@
 import Control.Concurrent hiding (ThreadId)
 import qualified Data.Binary.Put as P
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
 import qualified Data.ByteString.Lazy as BL
+import Data.Char (isPrint)
 import Data.IntMap (IntMap)
 import qualified Data.IntMap as IM
 import Data.Function hiding (id)
 import Data.List
 import Data.String (IsString)
 import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
 import qualified Data.Text.Lazy as TL
 import qualified Data.Text.Lazy.Builder as TB
 import qualified Data.Text.Lazy.Builder.Int as TB
@@ -485,6 +488,20 @@
 
         ProfBegin {..} ->
           "start time profiling, tick interval " <> TB.decimal profTickInterval <> " (ns)"
+
+        UserBinaryMessage {..} ->
+          "binary message " <> TB.fromText (replaceUnprintableWith '.' payload)
+
+-- | Replace unprintable bytes in the message with the replacement character
+replaceUnprintableWith
+  :: Char -- ^ Replacement character
+  -> B.ByteString -- ^ Binary message which may contain unprintable bytes
+  -> T.Text
+replaceUnprintableWith replacement = TE.decodeUtf8 . B8.map replace
+  where
+    replace c
+      | isPrint c = c
+      | otherwise = replacement
 
 buildFilters :: [T.Text] -> Maybe TB.Builder
 buildFilters = foldr g Nothing
diff --git a/src/GHC/RTS/Events/Binary.hs b/src/GHC/RTS/Events/Binary.hs
--- a/src/GHC/RTS/Events/Binary.hs
+++ b/src/GHC/RTS/Events/Binary.hs
@@ -14,6 +14,7 @@
   , ghc782StopParser
   , post782StopParser
   , parRTSParsers
+  , binaryEventParsers
 
   -- * Writers
   , putEventLog
@@ -851,6 +852,14 @@
       (return ())
     return $! ProfSampleCostCentre {..} ]
 
+binaryEventParsers :: [EventParser EventInfo]
+binaryEventParsers =
+  [ VariableSizeParser EVENT_USER_BINARY_MSG $ do
+    payloadLen <- get :: Get Word16
+    payload <- G.getByteString $ fromIntegral payloadLen
+    return $! UserBinaryMessage { payload }
+  ]
+
 -- | String byte length in the eventlog format. It includes
 -- 1 byte for NUL.
 textByteLen :: T.Text -> Int
@@ -996,7 +1005,7 @@
     HeapProfSampleString {} -> EVENT_HEAP_PROF_SAMPLE_STRING
     ProfSampleCostCentre {} -> EVENT_PROF_SAMPLE_COST_CENTRE
     ProfBegin {}            -> EVENT_PROF_BEGIN
-
+    UserBinaryMessage {} -> EVENT_USER_BINARY_MSG
 
 nEVENT_PERF_NAME, nEVENT_PERF_COUNTER, nEVENT_PERF_TRACEPOINT :: EventTypeNum
 nEVENT_PERF_NAME = EVENT_PERF_NAME
@@ -1419,6 +1428,9 @@
 putEventSpec ProfBegin {..} = do
     putE profTickInterval
 
+putEventSpec UserBinaryMessage {..} = do
+    putE (fromIntegral (B.length payload) :: Word16)
+    putByteString payload
 
 -- [] == []
 -- [x] == x\0
diff --git a/src/GHC/RTS/Events/Incremental.hs b/src/GHC/RTS/Events/Incremental.hs
--- a/src/GHC/RTS/Events/Incremental.hs
+++ b/src/GHC/RTS/Events/Incremental.hs
@@ -203,5 +203,6 @@
         , perfParsers
         , heapProfParsers
         , timeProfParsers
+        , binaryEventParsers
         ]
     parsers = EventParsers $ mkEventTypeParsers imap event_parsers
diff --git a/test/Utils.hs b/test/Utils.hs
--- a/test/Utils.hs
+++ b/test/Utils.hs
@@ -16,6 +16,7 @@
     , "hello-ghc-8.2.2.eventlog", "hello-ghc-8.6.5.eventlog"
     , "biographical-samples.eventlog"
     , "time-prof.eventlog"
+    , "trace-binary-event.eventlog"
     ]
 
 
diff --git a/test/trace-binary-event.eventlog b/test/trace-binary-event.eventlog
new file mode 100644
Binary files /dev/null and b/test/trace-binary-event.eventlog differ
diff --git a/test/trace-binary-event.eventlog.reference b/test/trace-binary-event.eventlog.reference
new file mode 100644
--- /dev/null
+++ b/test/trace-binary-event.eventlog.reference
@@ -0,0 +1,77 @@
+Event Types:
+0: Create thread (size 4)
+1: Run thread (size 4)
+2: Stop thread (size 10)
+3: Thread runnable (size 4)
+4: Migrate thread (size 6)
+8: Wakeup thread (size 6)
+9: Starting GC (size 0)
+10: Finished GC (size 0)
+11: Request sequential GC (size 0)
+12: Request parallel GC (size 0)
+15: Create spark thread (size 4)
+16: Log message (size variable)
+18: Block marker (size 14)
+19: User message (size variable)
+20: GC idle (size 0)
+21: GC working (size 0)
+22: GC done (size 0)
+25: Create capability set (size 6)
+26: Delete capability set (size 4)
+27: Add capability to capability set (size 6)
+28: Remove capability from capability set (size 6)
+29: RTS name and version (size variable)
+30: Program arguments (size variable)
+31: Program environment variables (size variable)
+32: Process ID (size 8)
+33: Parent process ID (size 8)
+34: Spark counters (size 56)
+35: Spark create (size 0)
+36: Spark dud (size 0)
+37: Spark overflow (size 0)
+38: Spark run (size 0)
+39: Spark steal (size 2)
+40: Spark fizzle (size 0)
+41: Spark GC (size 0)
+43: Wall clock time (size 16)
+44: Thread label (size variable)
+45: Create capability (size 2)
+46: Delete capability (size 2)
+47: Disable capability (size 2)
+48: Enable capability (size 2)
+49: Total heap mem ever allocated (size 12)
+50: Current heap size (size 12)
+51: Current heap live data (size 12)
+52: Heap static parameters (size 38)
+53: GC statistics (size 58)
+54: Synchronise stop-the-world GC (size 0)
+55: Task create (size 18)
+56: Task migrate (size 12)
+57: Task delete (size 8)
+58: User marker (size variable)
+59: Empty event for bug #9003 (size 0)
+160: Start of heap profile (size variable)
+161: Cost center definition (size variable)
+162: Start of heap profile sample (size 8)
+163: Heap profile cost-centre sample (size variable)
+164: Heap profile string sample (size variable)
+181: User binary message (size variable)
+
+Events:
+199116: created capset 0 of type CapsetOsProcess
+199197: created capset 1 of type CapsetClockDomain
+199989: created cap 0
+200039: assigned cap 0 to capset 0
+200099: assigned cap 0 to capset 1
+205279: capset 1: wall clock time 1574408715s 234903000ns (unix epoch)
+205437: capset 0: pid 49933
+211311: capset 0: parent pid 44446
+215666: capset 0: RTS version "GHC-8.8.1 rts_l"
+219032: capset 0: args: ["./trace-binary-event","+RTS","-l-au"]
+2871512: cap 0: binary message Hello, .
+15687612: removed cap 0 from capset 0
+15687840: removed cap 0 from capset 1
+15688438: deleted cap 0
+15688758: deleted capset 0
+15688911: deleted capset 1
+
