diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for ghctags
 
+## 0.6.0.0 -- 2023-05-01
+
+- `GHC-9.6` support; dropped support of `GHC-8.8`.
+
 ## 0.5.1.0
 
 - tags for local bindings (from `where` clauses)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 ========================
 [![Haskell](https://img.shields.io/badge/language-Haskell-8D82AC.svg?style=for-the-badge)](https://haskell.org)
 [![MPL-2.0 License](http://img.shields.io/badge/license-MPL20-brightgreen.svg?style=for-the-badge)](https://github.com/coot/ghc-tags-plugin/blob/master/ghc-tags-core/LICENSE)
-[![Haskell CI](https://img.shields.io/github/workflow/status/coot/ghc-tags-plugin/Haskell%20CI?label=Build&style=for-the-badge)](https://github.com/coot/ghc-tags-plugin/actions/workflows/ci.yml)
+[![Haskell CI](https://img.shields.io/github/actions/workflow/status/coot/ghc-tags-plugin/ci.yml?branch=master&label=Build&style=for-the-badge)](https://github.com/coot/ghc-tags-plugin/actions/workflows/ci.yml)
 
 A library and a [GHC compiler
 plugin](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/extending_ghc.html#compiler-plugins)
diff --git a/ghc-tags-plugin.cabal b/ghc-tags-plugin.cabal
--- a/ghc-tags-plugin.cabal
+++ b/ghc-tags-plugin.cabal
@@ -1,6 +1,6 @@
 cabal-version:       3.0
 name:                ghc-tags-plugin
-version:             0.5.3.0
+version:             0.6.0.0
 synopsis:            A compiler plugin which generates tags file from GHC parsed syntax tree.
 description:
   A [GHC compiler plugin](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/extending_ghc.html?highlight=compiler%20plugin#compiler-plugins)
@@ -18,7 +18,7 @@
                      README.md
 homepage:            https://github.com/coot/ghc-tags-plugin#readme
 bug-reports:         https://github.com/coot/ghc-tags-plugin/issues
-tested-with:         GHC == { 8.10.7, 9.0.2, 9.2.4, 9.4.2 }
+tested-with:         GHC == { 8.10, 9.0, 9.2, 9.4, 9.6 }
 
 -- Don't build gtp-check command by default; it's a development tool.
 flag gtp-check
@@ -52,15 +52,13 @@
   other-modules:       Plugin.GhcTags.CTag
                        Paths_ghc_tags_plugin
   autogen-modules:     Paths_ghc_tags_plugin
-  build-depends:       base              >=4.12.0.0 && <4.18,
+  build-depends:       base              >=4.12.0.0 && <4.19,
                        bytestring        >=0.10 && < 0.12,
                        directory        ^>=1.3,
                        filepath         ^>=1.4,
-                       filepath-bytestring
-                                        ^>=1.4,
                        ghc               >=8.4 && <10,
                        lukko             >=0.1,
-                       mtl              ^>=2.2,
+                       mtl               >=2.2 && <2.4,
                        optparse-applicative
                                          >=0.15.1 && < 0.17,
                        pipes            ^>=4.3,
diff --git a/lib/Plugin/GhcTags.hs b/lib/Plugin/GhcTags.hs
--- a/lib/Plugin/GhcTags.hs
+++ b/lib/Plugin/GhcTags.hs
@@ -11,27 +11,31 @@
 module Plugin.GhcTags ( plugin, Options (..) ) where
 
 import           Control.Exception
+import           Control.Monad (when)
+#if __GLASGOW_HASKELL__ >= 906
 import           Control.Monad.State.Strict
+#else
+import           Control.Monad.State.Strict hiding (when, void)
+#endif
 import           Data.ByteString (ByteString)
 import qualified Data.ByteString         as BS
 import qualified Data.ByteString.Char8   as BSC
 import qualified Data.ByteString.Lazy    as BSL
 import qualified Data.ByteString.Builder as BB
+import           Data.Functor (void)
 import qualified Data.Text as Text
 import qualified Data.Text.Encoding as Text
 import           Data.Functor.Identity (Identity (..))
 import           Data.List (sortBy)
-#if __GLASGOW_HASKELL__ < 810
-import           Data.Either (rights)
-#else
 import           Data.Either (partitionEithers, rights)
-#endif
 import           Data.Foldable (traverse_)
 import           Data.Maybe (mapMaybe)
+#if __GLASGOW_HASKELL__ > 906
+import           System.Directory.OsPath
+#else
 import           System.Directory
-import           System.FilePath
-import           System.FilePath.ByteString (RawFilePath)
-import qualified System.FilePath.ByteString as FilePath
+#endif
+import qualified System.FilePath as FilePath
 import           System.IO
 
 import           Options.Applicative.Types (ParserFailure (..))
@@ -113,22 +117,17 @@
 import           GHC.Driver.Session (DynFlags)
 #elif __GLASGOW_HASKELL__ >= 900
 import           GHC.Driver.Session (DynFlags (DynFlags, hooks))
-#elif __GLASGOW_HASKELL__ >= 810
-import           DynFlags (DynFlags (DynFlags, hooks))
 #else
-import           DynFlags (DynFlags)
+import           DynFlags (DynFlags (DynFlags, hooks))
 #endif
 
 #if   __GLASGOW_HASKELL__ >= 900
 import           GHC.Hs (GhcPs, GhcTc, HsModule (..), LHsDecl, LHsExpr)
-#elif __GLASGOW_HASKELL__ >= 810
+#else
 import           GHC.Hs (GhcPs, GhcTc, HsModule (..), LHsDecl, LHsExpr)
 import           TcSplice
 import           TcRnMonad
 import           Hooks
-#else
-import           HsExtension (GhcPs)
-import           HsSyn (HsModule (..))
 #endif
 #if __GLASGOW_HASKELL__ >= 900
 import           GHC.Utils.Outputable (($+$), ($$))
@@ -141,10 +140,8 @@
 #endif
 #if   __GLASGOW_HASKELL__ >= 900
 import           GHC.Data.FastString (bytesFS)
-#elif __GLASGOW_HASKELL__ >= 810
-import           FastString          (bytesFS)
 #else
-import           FastString          (FastString (fs_bs))
+import           FastString          (bytesFS)
 #endif
 
 import           GhcTags.Ghc
@@ -158,12 +155,9 @@
 import qualified Plugin.GhcTags.CTag as CTag
 
 
-#if   __GLASGOW_HASKELL__ < 810
-bytesFS :: FastString -> ByteString
-bytesFS = fs_bs
-#endif
-
-#if   __GLASGOW_HASKELL__ >= 900
+#if   __GLASGOW_HASKELL__ >= 906
+type GhcPsModule = HsModule GhcPs
+#elif __GLASGOW_HASKELL__ >= 900
 type GhcPsModule = HsModule
 #else
 type GhcPsModule = HsModule GhcPs
@@ -209,7 +203,7 @@
 #endif
 #if   __GLASGOW_HASKELL__ >= 902
       driverPlugin       = ghcTagsDriverPlugin,
-#elif __GLASGOW_HASKELL__ >= 810
+#else
       dynflagsPlugin     = ghcTagsDynflagsPlugin,
 #endif
       pluginRecompile    = GhcPlugins.purePlugin
@@ -251,8 +245,8 @@
                                 (displayException ioerr))
                      throwIO (GhcTagsParserPluginIOException ioerr)) $
 
-                let lockFile = case splitFileName tagsFile of
-                      (dir, name) -> dir </> "." ++ name ++ ".lock" in
+                let lockFile = case FilePath.splitFileName tagsFile of
+                      (dir, name) -> dir FilePath.</> "." ++ name ++ ".lock" in
                 -- Take advisory exclusive lock (a BSD lock using `flock`) on the tags
                 -- file.  This is needed when `cabal` compiles in parallel.
                 -- We take the lock on the copy, otherwise the lock would be removed when
@@ -334,8 +328,8 @@
     -- is then renamed to tags file.
     updateCTags_stream = do
       tagsFileExists <- doesFileExist tagsFile
-      let destFile = case splitFileName tagsFile of
-            (dir, name) -> dir </> "." ++ name
+      let destFile = case FilePath.splitFileName tagsFile of
+            (dir, name) -> dir FilePath.</> "." ++ name
 
       mbInSize <-
         if debug
@@ -348,14 +342,14 @@
 
       withFile destFile WriteMode  $ \writeHandle ->
         withFile tagsFile ReadWriteMode $ \readHandle -> do
-          cwd <- BSC.pack <$> getCurrentDirectory
+          cwd <- rawFilePathFromBS . BSC.pack <$> getCurrentDirectory
           -- absolute directory path of the tags file; we need canonical path
           -- (without ".." and ".") to make 'makeRelative' works.
-          tagsDir <- BSC.pack <$> canonicalizePath (fst $ splitFileName tagsFile)
+          tagsDir <- rawFilePathFromBS . BSC.pack <$> canonicalizePath (fst $ FilePath.splitFileName tagsFile)
           case ml_hs_file ms_location of
             Nothing         -> pure ()
             Just sourcePath -> do
-              let sourcePathBS = Text.encodeUtf8 (Text.pack sourcePath)
+              let sourcePathBS = rawFilePathFromBS $ Text.encodeUtf8 (Text.pack sourcePath)
                   -- path of the compiled module; it is relative to the cabal file,
                   -- not the project.
                   modulePath =
@@ -365,7 +359,8 @@
 #else
                       GHC.RealSrcSpan rss ->
 #endif
-                          bytesFS
+                          rawFilePathFromBS
+                        . bytesFS
                         . GHC.srcSpanFile
                         $ rss
                       GHC.UnhelpfulSpan {} ->
@@ -468,14 +463,14 @@
                         then BS.readFile tagsFile
                         else return mempty
       withFile tagsFile WriteMode $ \writeHandle -> do
-        cwd <- BSC.pack <$> getCurrentDirectory
+        cwd <- rawFilePathFromBS . BSC.pack <$> getCurrentDirectory
         -- absolute directory path of the tags file; we need canonical path
         -- (without ".." and ".") to make 'makeRelative' works.
-        tagsDir <- BSC.pack <$> canonicalizePath (fst $ splitFileName tagsFile)
+        tagsDir <- rawFilePathFromBS . BSC.pack <$> canonicalizePath (fst $ FilePath.splitFileName tagsFile)
         case ml_hs_file ms_location of
           Nothing         -> pure ()
           Just sourcePath -> do
-            let sourcePathBS = Text.encodeUtf8 (Text.pack sourcePath)
+            let sourcePathBS = rawFilePathFromBS $ Text.encodeUtf8 (Text.pack sourcePath)
                 -- path of the compiled module; it is relative to the cabal file,
                 -- not the project.
                 modulePath =
@@ -485,7 +480,8 @@
 #else
                     GHC.RealSrcSpan rss ->
 #endif
-                        bytesFS
+                        rawFilePathFromBS
+                      . bytesFS
                       . GHC.srcSpanFile
                       $ rss
                     GHC.UnhelpfulSpan {} ->
@@ -553,10 +549,10 @@
                         then BS.readFile tagsFile
                         else return mempty
       withFile tagsFile WriteMode $ \writeHandle -> do
-          cwd <- BSC.pack <$> getCurrentDirectory
+          cwd <- rawFilePathFromBS . BSC.pack <$> getCurrentDirectory
           -- absolute directory path of the tags file; we need canonical path
           -- (without ".." and ".") to make 'makeRelative' works.
-          tagsDir <- BSC.pack <$> canonicalizePath (fst $ splitFileName tagsFile)
+          tagsDir <- rawFilePathFromBS . BSC.pack <$> canonicalizePath (fst $ FilePath.splitFileName tagsFile)
 
           case ml_hs_file ms_location of
             Nothing         -> pure ()
@@ -570,7 +566,8 @@
                   printMessageDoc dynFlags ParserException (Just ms_mod) err
 
                 Right (Right parsedTags) -> do
-                  let sourcePathBS = Text.encodeUtf8 (Text.pack sourcePath)
+                  let sourcePathBS = rawFilePathFromBS
+                                   $ Text.encodeUtf8 (Text.pack sourcePath)
 
                       tags :: [ETag]
                       tags = filterAdjacentTags
@@ -643,7 +640,6 @@
       _  -> map Just (tail tags) ++ [Nothing]
 
 
-#if __GLASGOW_HASKELL__ >= 810
 --
 -- Tags for Template-Haskell splices
 --
@@ -679,8 +675,8 @@
                                (displayException ioerr))
                      throwIO (GhcTagsDynFlagsPluginIOException ioerr)) $
             withFileLock debug tagsFile ExclusiveLock $ \_ -> do
-            cwd <- BSC.pack <$> getCurrentDirectory
-            tagsDir <- BSC.pack <$> canonicalizePath (fst $ splitFileName tagsFile)
+            cwd <- rawFilePathFromBS . BSC.pack <$> getCurrentDirectory
+            tagsDir <- rawFilePathFromBS . BSC.pack <$> canonicalizePath (fst $ FilePath.splitFileName tagsFile)
             tagsContent <- BSC.readFile tagsFile
             if etags
               then do
@@ -694,7 +690,7 @@
                         tags' = sortBy ETag.compareTags $
                                   tags
                                   ++
-                                  (fmap (fixTagFilePath  cwd tagsDir)
+                                  (fmap (fixTagFilePath cwd tagsDir)
                                   . ghcTagToTag SingETag dynFlags)
                                     `mapMaybe`
                                      hsDeclsToGhcTags Nothing decls
@@ -712,7 +708,7 @@
                                 sortBy CTag.compareTags
                                 ( tags
                                   ++
-                                  (fmap (fixTagFilePath  cwd tagsDir)
+                                  (fmap (fixTagFilePath cwd tagsDir)
                                     . ghcTagToTag SingCTag dynFlags)
                                     `mapMaybe`
                                     hsDeclsToGhcTags Nothing decls
@@ -744,7 +740,6 @@
         res <- metaRequestD h e
         k res <$ f res
       MetaAW k -> k <$> metaRequestAW h e
-#endif
 
 
 --
@@ -759,9 +754,9 @@
             -- ^ tag's file path
             -> RawFilePath
 fixFilePath cwd tagsDir =
-    FilePath.normalise
-  . FilePath.makeRelative tagsDir
-  . (cwd FilePath.</>)
+    normaliseRawFilePath
+  . makeRelativeRawFilePath tagsDir
+  . (cwd </>)
 
 
 -- we are missing `Text` based `FilePath` library!
@@ -773,9 +768,9 @@
 fixTagFilePath cwd tagsDir tag@Tag { tagFilePath = TagFilePath fp } =
   tag { tagFilePath =
           TagFilePath
-            (Text.decodeUtf8
-              (fixFilePath cwd tagsDir
-                (Text.encodeUtf8 fp)))
+            ( Text.decodeUtf8 . rawFilePathToBS
+            $ fixFilePath cwd tagsDir
+                          (rawFilePathFromBS $ Text.encodeUtf8 fp))
       }
 
 --
