diff --git a/conf/frps_full_example.toml b/conf/frps_full_example.toml
index a4fc2736..fa04c55e 100644
--- a/conf/frps_full_example.toml
+++ b/conf/frps_full_example.toml
@@ -89,6 +89,8 @@ log.level = "info"
 log.maxDays = 3
 # disable log colors when log.to is console, default is false
 log.disablePrintColor = false
+# log the duration of each connection name has string 'ssh' or 'rdp'.
+log.durationtypes = "ssh,rdp"
 
 # DetailedErrorsToClient defines whether to send the specific error (with debug info) to frpc. By default, this value is true.
 detailedErrorsToClient = true
diff --git a/conf/legacy/frps_legacy_full.ini b/conf/legacy/frps_legacy_full.ini
index 525072dc..b2b20f9f 100644
--- a/conf/legacy/frps_legacy_full.ini
+++ b/conf/legacy/frps_legacy_full.ini
@@ -70,6 +70,12 @@ log_max_days = 3
 # disable log colors when log_file is console, default is false
 disable_log_color = false
 
+# log the duration of each connection for the connection type identified by its name
+# examples,
+#   'log_duration_types = ssh,rdp', it will log the duration for connection name has string 'ssh' or 'rdp'.
+#   'log_duration_types = all', it will log the duration for all connections.
+log_duration_types = ssh,rdp
+
 # DetailedErrorsToClient defines whether to send the specific error (with debug info) to frpc. By default, this value is true.
 detailed_errors_to_client = true
 
diff --git a/pkg/config/flags.go b/pkg/config/flags.go
index 6027b622..a318d3ab 100644
--- a/pkg/config/flags.go
+++ b/pkg/config/flags.go
@@ -243,6 +243,7 @@ func RegisterServerConfigFlags(cmd *cobra.Command, c *v1.ServerConfig, opts ...R
 	cmd.PersistentFlags().StringVarP(&c.Log.Level, "log_level", "", "info", "log level")
 	cmd.PersistentFlags().Int64VarP(&c.Log.MaxDays, "log_max_days", "", 3, "log max days")
 	cmd.PersistentFlags().BoolVarP(&c.Log.DisablePrintColor, "disable_log_color", "", false, "disable log color in console")
+	cmd.PersistentFlags().StringVarP(&c.Log.DurationTypes, "log_duration_types", "", "", "log duration types")
 	cmd.PersistentFlags().StringVarP(&c.Auth.Token, "token", "t", "", "auth token")
 	cmd.PersistentFlags().StringVarP(&c.SubDomainHost, "subdomain_host", "", "", "subdomain host")
 	cmd.PersistentFlags().VarP(&PortsRangeSliceFlag{V: &c.AllowPorts}, "allow_ports", "", "allow ports")
diff --git a/pkg/config/legacy/conversion.go b/pkg/config/legacy/conversion.go
index dd8c4a11..59f33a12 100644
--- a/pkg/config/legacy/conversion.go
+++ b/pkg/config/legacy/conversion.go
@@ -133,6 +133,7 @@ func Convert_ServerCommonConf_To_v1(conf *ServerCommonConf) *v1.ServerConfig {
 	out.Log.Level = conf.LogLevel
 	out.Log.MaxDays = conf.LogMaxDays
 	out.Log.DisablePrintColor = conf.DisableLogColor
+	out.Log.DurationTypes = conf.LogDurationTypes
 
 	out.DetailedErrorsToClient = lo.ToPtr(conf.DetailedErrorsToClient)
 	out.SubDomainHost = conf.SubDomainHost
diff --git a/pkg/config/legacy/server.go b/pkg/config/legacy/server.go
index 1cfa1bdc..0d31e6e2 100644
--- a/pkg/config/legacy/server.go
+++ b/pkg/config/legacy/server.go
@@ -125,6 +125,11 @@ type ServerCommonConf struct {
 	// DisableLogColor disables log colors when LogWay == "console" when set to
 	// true. By default, this value is false.
 	DisableLogColor bool `ini:"disable_log_color" json:"disable_log_color"`
+	// LogDurationTypes specifies the types of connection names for which the
+	// duration will be logged. If set to 'ssh,rdp', it will log the duration
+	// of connections named 'ssh', 'ssh_1', 'sshname', 'rdp', 'rdp_test1', or
+	// 'web_my_rdp'. By default, this value is "".
+	LogDurationTypes string `ini:"log_duration_types" json:"log_duration_types"`
 	// DetailedErrorsToClient defines whether to send the specific error (with
 	// debug info) to frpc. By default, this value is true.
 	DetailedErrorsToClient bool `ini:"detailed_errors_to_client" json:"detailed_errors_to_client"`
@@ -210,6 +215,7 @@ func GetDefaultServerConf() ServerCommonConf {
 		DashboardAddr:          "0.0.0.0",
 		LogFile:                "console",
 		LogWay:                 "console",
+		LogDurationTypes:       "",
 		DetailedErrorsToClient: true,
 		TCPMux:                 true,
 		AllowPorts:             make(map[int]struct{}),
diff --git a/pkg/config/v1/common.go b/pkg/config/v1/common.go
index ddb23356..861919d9 100644
--- a/pkg/config/v1/common.go
+++ b/pkg/config/v1/common.go
@@ -110,12 +110,18 @@ type LogConfig struct {
 	MaxDays int64 `json:"maxDays"`
 	// DisablePrintColor disables log colors when log.to is "console".
 	DisablePrintColor bool `json:"disablePrintColor,omitempty"`
+	// DurationTypes specifies the types of connection names for which the
+	// duration will be logged. If set to 'ssh,rdp', it will log the duration
+	// of connections named 'ssh', 'ssh_1', 'sshname', 'rdp', 'rdp_test1', or
+	// 'web_my_rdp'. By default, this value is "".
+	DurationTypes string `json:"durationtypes,omitempty"`
 }
 
 func (c *LogConfig) Complete() {
 	c.To = util.EmptyOr(c.To, "console")
 	c.Level = util.EmptyOr(c.Level, "info")
 	c.MaxDays = util.EmptyOr(c.MaxDays, 3)
+	c.DurationTypes = util.EmptyOr(c.DurationTypes, "")
 }
 
 type HTTPPluginOptions struct {
diff --git a/server/proxy/proxy.go b/server/proxy/proxy.go
index c7c18c32..862a943d 100644
--- a/server/proxy/proxy.go
+++ b/server/proxy/proxy.go
@@ -21,6 +21,7 @@ import (
 	"net"
 	"reflect"
 	"strconv"
+	"strings"
 	"sync"
 	"time"
 
@@ -62,6 +63,7 @@ type Proxy interface {
 
 type BaseProxy struct {
 	name          string
+	logDuration   bool
 	rc            *controller.ResourceController
 	listeners     []net.Listener
 	usedPortsNum  int
@@ -258,6 +260,7 @@ func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
 		})
 	}
 
+	startime := time.Now().UnixNano() / 1000000 // time in microseconds
 	xl.Debugf("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
 		workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
 
@@ -268,7 +271,34 @@ func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
 	metrics.Server.CloseConnection(name, proxyType)
 	metrics.Server.AddTrafficIn(name, proxyType, inCount)
 	metrics.Server.AddTrafficOut(name, proxyType, outCount)
-	xl.Debugf("join connections closed")
+
+	// Log the duration of connection.
+	if pxy.logDuration {
+		endtime := time.Now().UnixNano() / 1000000 // time in microseconds
+		connectionDuration := endtime - startime
+		xl.Debugf("join connection closed, it remains [%d]ms, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", connectionDuration,
+			workConn.LocalAddr().String(), workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
+		xl.Infof("connection closed, it remains [%d]ms, userConn(l[%s] r[%s])", connectionDuration,
+			userConn.LocalAddr().String(), userConn.RemoteAddr().String())
+	} else {
+		xl.Debugf("join connection closed, userConn(l[%s] r[%s])", userConn.LocalAddr().String(), userConn.RemoteAddr().String())
+	}
+}
+
+// Check Duration should be loged or not. True: while connection name contain a string in logDurationTypes.
+func IsTheTypeToLog(logDurationTypes string, name string, xl *xlog.Logger) bool {
+	if strings.Contains(logDurationTypes, "all") {
+		xl.Infof("The duration of each connection through this Proxy will be logged.")
+		return true
+	}
+	thestrlist := strings.Split(logDurationTypes, ",")
+	for i := 0; i < len(thestrlist); i++ {
+		if (thestrlist[i] != "") && strings.Contains(name, thestrlist[i]) {
+			xl.Infof("The duration of each connection through this Proxy will be logged.")
+			return true
+		}
+	}
+	return false
 }
 
 type Options struct {
@@ -293,6 +323,7 @@ func NewProxy(ctx context.Context, options *Options) (pxy Proxy, err error) {
 
 	basePxy := BaseProxy{
 		name:          configurer.GetBaseConfig().Name,
+		logDuration:   IsTheTypeToLog(options.ServerCfg.Log.DurationTypes, configurer.GetBaseConfig().Name, xl),
 		rc:            options.ResourceController,
 		listeners:     make([]net.Listener, 0),
 		poolCount:     options.PoolCount,