Index: /trunk/downstream.go
===================================================================
--- /trunk/downstream.go	(revision 102)
+++ /trunk/downstream.go	(revision 103)
@@ -192,5 +192,5 @@
 }
 
-func (dc *downstreamConn) readMessages() error {
+func (dc *downstreamConn) readMessages(ch chan<- downstreamIncomingMessage) error {
 	dc.logger.Printf("new connection")
 
@@ -207,15 +207,5 @@
 		}
 
-		err = dc.handleMessage(msg)
-		if ircErr, ok := err.(ircError); ok {
-			ircErr.Message.Prefix = dc.srv.prefix()
-			dc.SendMessage(ircErr.Message)
-		} else if err != nil {
-			return fmt.Errorf("failed to handle IRC command %q: %v", msg.Command, err)
-		}
-
-		if dc.isClosed() {
-			return nil
-		}
+		ch <- downstreamIncomingMessage{msg, dc}
 	}
 
@@ -485,4 +475,25 @@
 }
 
+func (dc *downstreamConn) runUntilRegistered() error {
+	for !dc.registered {
+		msg, err := dc.irc.ReadMessage()
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			return fmt.Errorf("failed to read IRC command: %v", err)
+		}
+
+		err = dc.handleMessage(msg)
+		if ircErr, ok := err.(ircError); ok {
+			ircErr.Message.Prefix = dc.srv.prefix()
+			dc.SendMessage(ircErr.Message)
+		} else if err != nil {
+			return fmt.Errorf("failed to handle IRC command %q: %v", msg, err)
+		}
+	}
+
+	return nil
+}
+
 func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
 	switch msg.Command {
Index: /trunk/server.go
===================================================================
--- /trunk/server.go	(revision 102)
+++ /trunk/server.go	(revision 103)
@@ -115,6 +115,10 @@
 			s.lock.Unlock()
 
-			if err := dc.readMessages(); err != nil {
-				dc.logger.Printf("failed to handle messages: %v", err)
+			if err := dc.runUntilRegistered(); err != nil {
+				dc.logger.Print(err)
+			} else {
+				if err := dc.readMessages(dc.user.downstreamIncoming); err != nil {
+					dc.logger.Print(err)
+				}
 			}
 			dc.Close()
Index: /trunk/upstream.go
===================================================================
--- /trunk/upstream.go	(revision 102)
+++ /trunk/upstream.go	(revision 103)
@@ -660,5 +660,5 @@
 }
 
-func (uc *upstreamConn) readMessages() error {
+func (uc *upstreamConn) readMessages(ch chan<- upstreamIncomingMessage) error {
 	for {
 		msg, err := uc.irc.ReadMessage()
@@ -673,7 +673,5 @@
 		}
 
-		if err := uc.handleMessage(msg); err != nil {
-			uc.logger.Printf("failed to handle message %q: %v", msg, err)
-		}
+		ch <- upstreamIncomingMessage{msg, uc}
 	}
 
Index: /trunk/user.go
===================================================================
--- /trunk/user.go	(revision 102)
+++ /trunk/user.go	(revision 103)
@@ -4,5 +4,17 @@
 	"sync"
 	"time"
+
+	"gopkg.in/irc.v3"
 )
+
+type upstreamIncomingMessage struct {
+	msg *irc.Message
+	uc  *upstreamConn
+}
+
+type downstreamIncomingMessage struct {
+	msg *irc.Message
+	dc  *downstreamConn
+}
 
 type network struct {
@@ -41,5 +53,5 @@
 		net.user.lock.Unlock()
 
-		if err := uc.readMessages(); err != nil {
+		if err := uc.readMessages(net.user.upstreamIncoming); err != nil {
 			uc.logger.Printf("failed to handle messages: %v", err)
 		}
@@ -56,4 +68,7 @@
 	srv *Server
 
+	upstreamIncoming   chan upstreamIncomingMessage
+	downstreamIncoming chan downstreamIncomingMessage
+
 	lock            sync.Mutex
 	networks        []*network
@@ -63,6 +78,8 @@
 func newUser(srv *Server, record *User) *user {
 	return &user{
-		User: *record,
-		srv:  srv,
+		User:               *record,
+		srv:                srv,
+		upstreamIncoming:   make(chan upstreamIncomingMessage, 64),
+		downstreamIncoming: make(chan downstreamIncomingMessage, 64),
 	}
 }
@@ -120,4 +137,24 @@
 	}
 	u.lock.Unlock()
+
+	for {
+		select {
+		case upstreamMsg := <-u.upstreamIncoming:
+			msg, uc := upstreamMsg.msg, upstreamMsg.uc
+			if err := uc.handleMessage(msg); err != nil {
+				uc.logger.Printf("failed to handle message %q: %v", msg, err)
+			}
+		case downstreamMsg := <-u.downstreamIncoming:
+			msg, dc := downstreamMsg.msg, downstreamMsg.dc
+			err := dc.handleMessage(msg)
+			if ircErr, ok := err.(ircError); ok {
+				ircErr.Message.Prefix = dc.srv.prefix()
+				dc.SendMessage(ircErr.Message)
+			} else if err != nil {
+				dc.logger.Printf("failed to handle message %q: %v", msg, err)
+				dc.Close()
+			}
+		}
+	}
 }
 
