diff --git a/go.mod b/go.mod
index 8ea1164d2..ed3a046b3 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,6 @@ require (
 	github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
 	github.com/go-chi/chi v4.1.2+incompatible
 	github.com/google/cel-go v0.6.0
-	github.com/jsternberg/zap-logfmt v1.2.0
 	github.com/klauspost/compress v1.11.3
 	github.com/klauspost/cpuid/v2 v2.0.1
 	github.com/lucas-clemente/quic-go v0.19.3
diff --git a/modules/logging/encoders.go b/modules/logging/encoders.go
index 79382dfcc..ab68f5e3f 100644
--- a/modules/logging/encoders.go
+++ b/modules/logging/encoders.go
@@ -22,7 +22,6 @@ import (
 
 	"github.com/caddyserver/caddy/v2"
 	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
-	zaplogfmt "github.com/jsternberg/zap-logfmt"
 	"go.uber.org/zap"
 	"go.uber.org/zap/buffer"
 	"go.uber.org/zap/zapcore"
@@ -31,7 +30,6 @@ import (
 func init() {
 	caddy.RegisterModule(ConsoleEncoder{})
 	caddy.RegisterModule(JSONEncoder{})
-	caddy.RegisterModule(LogfmtEncoder{})
 	caddy.RegisterModule(SingleFieldEncoder{})
 }
 
@@ -117,58 +115,6 @@ func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
 	return nil
 }
 
-// LogfmtEncoder encodes log entries as logfmt:
-// https://www.brandur.org/logfmt
-//
-// Note that logfmt does not encode nested structures
-// properly, so it is not a good fit for most logs.
-//
-// ⚠️ DEPRECATED. Do not use. It will eventually be removed
-// from the standard Caddy modules. For more information,
-// see https://github.com/caddyserver/caddy/issues/3575.
-type LogfmtEncoder struct {
-	zapcore.Encoder `json:"-"`
-	LogEncoderConfig
-}
-
-// CaddyModule returns the Caddy module information.
-func (LogfmtEncoder) CaddyModule() caddy.ModuleInfo {
-	return caddy.ModuleInfo{
-		ID:  "caddy.logging.encoders.logfmt",
-		New: func() caddy.Module { return new(LogfmtEncoder) },
-	}
-}
-
-// Provision sets up the encoder.
-func (lfe *LogfmtEncoder) Provision(ctx caddy.Context) error {
-	ctx.Logger(lfe).Warn("the logfmt encoder is DEPRECATED and will soon be removed from the standard modules",
-		zap.String("recommendation", "switch to a log format that isn't broken"),
-		zap.String("more_info", "https://github.com/caddyserver/caddy/issues/3575"))
-	lfe.Encoder = zaplogfmt.NewEncoder(lfe.ZapcoreEncoderConfig())
-	return nil
-}
-
-// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
-//
-//     logfmt {
-//         <common encoder config subdirectives...>
-//     }
-//
-// See the godoc on the LogEncoderConfig type for the syntax of
-// subdirectives that are common to most/all encoders.
-func (lfe *LogfmtEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
-	for d.Next() {
-		if d.NextArg() {
-			return d.ArgErr()
-		}
-		err := lfe.LogEncoderConfig.UnmarshalCaddyfile(d)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
 // SingleFieldEncoder writes a log entry that consists entirely
 // of a single string field in the log entry. This is useful
 // for custom, self-encoded log entries that consist of a
@@ -398,11 +344,9 @@ var bufferpool = buffer.NewPool()
 var (
 	_ zapcore.Encoder = (*ConsoleEncoder)(nil)
 	_ zapcore.Encoder = (*JSONEncoder)(nil)
-	_ zapcore.Encoder = (*LogfmtEncoder)(nil)
 	_ zapcore.Encoder = (*SingleFieldEncoder)(nil)
 
 	_ caddyfile.Unmarshaler = (*ConsoleEncoder)(nil)
 	_ caddyfile.Unmarshaler = (*JSONEncoder)(nil)
-	_ caddyfile.Unmarshaler = (*LogfmtEncoder)(nil)
 	_ caddyfile.Unmarshaler = (*SingleFieldEncoder)(nil)
 )