Index: /trunk/downstream.go
===================================================================
--- /trunk/downstream.go	(revision 728)
+++ /trunk/downstream.go	(revision 729)
@@ -1080,4 +1080,19 @@
 	}
 
+	if uc := dc.upstream(); uc != nil && uc.caps["draft/account-registration"] {
+		// Strip "before-connect", because we require downstreams to be fully
+		// connected before attempting account registration.
+		values := strings.Split(uc.supportedCaps["draft/account-registration"], ",")
+		for i, v := range values {
+			if v == "before-connect" {
+				values = append(values[:i], values[i+1:]...)
+				break
+			}
+		}
+		dc.setSupportedCap("draft/account-registration", strings.Join(values, ","))
+	} else {
+		dc.unsetSupportedCap("draft/account-registration")
+	}
+
 	if _, ok := dc.user.msgStore.(chatHistoryMessageStore); ok && dc.network != nil {
 		dc.setSupportedCap("draft/event-playback", "")
@@ -2409,5 +2424,4 @@
 		if uc == nil || !uc.caps["sasl"] {
 			return ircError{&irc.Message{
-				Prefix:  dc.srv.prefix(),
 				Command: irc.ERR_SASLFAIL,
 				Params:  []string{dc.nick, "Upstream network authentication not supported"},
@@ -2437,4 +2451,21 @@
 			})
 		}
+	case "REGISTER", "VERIFY":
+		// Check number of params here, since we'll use that to save the
+		// credentials on command success
+		if (msg.Command == "REGISTER" && len(msg.Params) < 3) || (msg.Command == "VERIFY" && len(msg.Params) < 2) {
+			return newNeedMoreParamsError(msg.Command)
+		}
+
+		uc := dc.upstream()
+		if uc == nil || !uc.caps["draft/account-registration"] {
+			return ircError{&irc.Message{
+				Command: "FAIL",
+				Params:  []string{msg.Command, "TEMPORARILY_UNAVAILABLE", "*", "Upstream network account registration not supported"},
+			}}
+		}
+
+		uc.logger.Printf("starting %v with account name %v", msg.Command, msg.Params[0])
+		uc.enqueueCommand(dc, msg)
 	case "MONITOR":
 		// MONITOR is unsupported in multi-upstream mode
Index: /trunk/upstream.go
===================================================================
--- /trunk/upstream.go	(revision 728)
+++ /trunk/upstream.go	(revision 729)
@@ -36,5 +36,6 @@
 	"setname":          true,
 
-	"draft/extended-monitor": true,
+	"draft/account-registration": true,
+	"draft/extended-monitor":     true,
 }
 
@@ -301,4 +302,10 @@
 					Params:  []string{dc.nick, "SASL authentication aborted"},
 				})
+			case "REGISTER", "VERIFY":
+				dc.SendMessage(&irc.Message{
+					Prefix:  dc.srv.prefix(),
+					Command: "FAIL",
+					Params:  []string{pendingCmd.msg.Command, "TEMPORARILY_UNAVAILABLE", pendingCmd.msg.Params[0], "Command aborted"},
+				})
 			default:
 				panic(fmt.Errorf("Unsupported pending command %q", pendingCmd.msg.Command))
@@ -319,5 +326,5 @@
 func (uc *upstreamConn) enqueueCommand(dc *downstreamConn, msg *irc.Message) {
 	switch msg.Command {
-	case "LIST", "WHO", "AUTHENTICATE":
+	case "LIST", "WHO", "AUTHENTICATE", "REGISTER", "VERIFY":
 		// Supported
 	default:
@@ -633,4 +640,19 @@
 				Params:  []string{"END"},
 			})
+		}
+	case "REGISTER", "VERIFY":
+		if dc, cmd := uc.dequeueCommand(msg.Command); dc != nil {
+			if msg.Command == "REGISTER" {
+				var account, password string
+				if err := parseMessageParams(msg, nil, &account); err != nil {
+					return err
+				}
+				if err := parseMessageParams(cmd, nil, nil, &password); err != nil {
+					return err
+				}
+				uc.network.autoSaveSASLPlain(context.TODO(), account, password)
+			}
+
+			dc.SendMessage(msg)
 		}
 	case irc.RPL_WELCOME:
@@ -1570,9 +1592,6 @@
 		}
 
-		if command == "LIST" || command == "WHO" {
-			dc, _ := uc.dequeueCommand(command)
-			if dc != nil && downstreamID == 0 {
-				downstreamID = dc.id
-			}
+		if dc, _ := uc.dequeueCommand(command); dc != nil && downstreamID == 0 {
+			downstreamID = dc.id
 		}
 
@@ -1583,4 +1602,17 @@
 				Params:  []string{dc.nick, command, reason},
 			})
+		})
+	case "FAIL":
+		var command string
+		if err := parseMessageParams(msg, &command); err != nil {
+			return err
+		}
+
+		if dc, _ := uc.dequeueCommand(command); dc != nil && downstreamID == 0 {
+			downstreamID = dc.id
+		}
+
+		uc.forEachDownstreamByID(downstreamID, func(dc *downstreamConn) {
+			dc.SendMessage(msg)
 		})
 	case "ACK":
