diff --git a/lib/backend/backends/v0/server.go b/lib/backend/backends/v0/server.go
index d40e36e46ae304a69910593fb265e5c73bfe6b2b..ea0257ca2dab0987072d7519edfb64fda4f524bc 100644
--- a/lib/backend/backends/v0/server.go
+++ b/lib/backend/backends/v0/server.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"net"
 
+	"pggat2/lib/auth/md5"
 	"pggat2/lib/auth/sasl"
 	"pggat2/lib/backend"
 	"pggat2/lib/pnet"
@@ -115,6 +116,20 @@ func (T *Server) authenticationSASL(mechanisms []string, username, password stri
 	return nil
 }
 
+func (T *Server) authenticationMD5(salt [4]byte, username, password string) error {
+	var builder packet.Builder
+	builder.Type(packet.AuthenticationResponse)
+	builder.String(md5.Encode(username, password, salt))
+	return T.Write(builder.Raw())
+}
+
+func (T *Server) authenticationCleartext(password string) error {
+	var builder packet.Builder
+	builder.Type(packet.AuthenticationResponse)
+	builder.String(password)
+	return T.Write(builder.Raw())
+}
+
 func (T *Server) startup0(username, password string) (bool, error) {
 	pkt, err := T.Read()
 	if err != nil {
@@ -138,9 +153,13 @@ func (T *Server) startup0(username, password string) (bool, error) {
 		case 2:
 			return false, errors.New("kerberos v5 is not supported")
 		case 3:
-			return false, errors.New("cleartext is not supported")
+			return false, T.authenticationCleartext(password)
 		case 5:
-			return false, errors.New("md5 password is not supported")
+			salt, ok := reader.Bytes(4)
+			if !ok {
+				return false, ErrBadPacketFormat
+			}
+			return false, T.authenticationMD5([4]byte(salt), username, password)
 		case 6:
 			return false, errors.New("scm credential is not supported")
 		case 7:
@@ -163,10 +182,10 @@ func (T *Server) startup0(username, password string) (bool, error) {
 
 			return false, T.authenticationSASL(mechanisms, username, password)
 		default:
-			// we only support protocol 3.0 for now
 			return false, errors.New("unknown authentication method")
 		}
 	case packet.NegotiateProtocolVersion:
+		// we only support protocol 3.0 for now
 		return false, errors.New("server wanted to negotiate protocol version")
 	default:
 		return false, ErrProtocolError
@@ -186,7 +205,7 @@ func (T *Server) startup1() (bool, error) {
 		if !ok {
 			return false, ErrBadPacketFormat
 		}
-		copy(T.cancellationKey[:], cancellationKey)
+		T.cancellationKey = [8]byte(cancellationKey)
 		return false, nil
 	case packet.ParameterStatus:
 		parameter, ok := reader.String()
diff --git a/lib/frontend/frontends/v0/client.go b/lib/frontend/frontends/v0/client.go
index 3b0a259e05b2da1e525fd6cec157b59d8fb6eb98..6678dd01ed2e5e39acf3e58f132dd951cda11f9f 100644
--- a/lib/frontend/frontends/v0/client.go
+++ b/lib/frontend/frontends/v0/client.go
@@ -3,6 +3,7 @@ package frontends
 import (
 	"crypto/rand"
 	"net"
+	"strings"
 
 	"pggat2/lib/auth/md5"
 	"pggat2/lib/auth/sasl"
@@ -46,13 +47,15 @@ type Client struct {
 
 	// cancellation key data
 	cancellationKey [8]byte
+	parameters      map[string]string
 }
 
 func NewClient(conn net.Conn) *Client {
 	client := &Client{
-		conn:   conn,
-		Reader: pnet.MakeReader(conn),
-		Writer: pnet.MakeWriter(conn),
+		conn:       conn,
+		Reader:     pnet.MakeReader(conn),
+		Writer:     pnet.MakeWriter(conn),
+		parameters: make(map[string]string),
 	}
 	err := client.accept()
 	if err != nil {
@@ -147,7 +150,12 @@ func (T *Client) startup0() (bool, perror.Error) {
 				"Replication mode is not supported yet",
 			)
 		default:
-			unsupportedOptions = append(unsupportedOptions, key)
+			if strings.HasPrefix(key, "_pq_.") {
+				// we don't support protocol extensions at the moment
+				unsupportedOptions = append(unsupportedOptions, key)
+			} else {
+				T.parameters[key] = value
+			}
 		}
 	}
 
@@ -309,6 +317,47 @@ func (T *Client) authenticationMD5(username, password string) perror.Error {
 	return nil
 }
 
+func (T *Client) authenticationCleartext(password string) perror.Error {
+	var builder packet.Builder
+	builder.Type(packet.Authentication)
+	builder.Uint32(3)
+
+	err := T.Write(builder.Raw())
+	if err != nil {
+		return WrapError(err)
+	}
+
+	// read password
+	pkt, err := T.Read()
+	if err != nil {
+		return WrapError(err)
+	}
+
+	reader := packet.MakeReader(pkt)
+	if reader.Type() != packet.AuthenticationResponse {
+		return perror.New(
+			perror.FATAL,
+			perror.ProtocolViolation,
+			"Expected password",
+		)
+	}
+
+	pw, ok := reader.String()
+	if !ok {
+		return ErrBadPacketFormat
+	}
+
+	if pw != password {
+		return perror.New(
+			perror.FATAL,
+			perror.InvalidPassword,
+			"Invalid password",
+		)
+	}
+
+	return nil
+}
+
 func (T *Client) accept() perror.Error {
 	for {
 		done, err := T.startup0()