diff --git a/App/Services/MutagenController.cs b/App/Services/MutagenController.cs
index dd489df..3a68962 100644
--- a/App/Services/MutagenController.cs
+++ b/App/Services/MutagenController.cs
@@ -85,7 +85,7 @@ public interface ISyncSessionController : IAsyncDisposable
     /// </summary>
     Task<SyncSessionControllerStateModel> RefreshState(CancellationToken ct = default);
 
-    Task<SyncSessionModel> CreateSyncSession(CreateSyncSessionRequest req, CancellationToken ct = default);
+    Task<SyncSessionModel> CreateSyncSession(CreateSyncSessionRequest req, Action<string> progressCallback, CancellationToken ct = default);
     Task<SyncSessionModel> PauseSyncSession(string identifier, CancellationToken ct = default);
     Task<SyncSessionModel> ResumeSyncSession(string identifier, CancellationToken ct = default);
     Task TerminateSyncSession(string identifier, CancellationToken ct = default);
@@ -200,12 +200,15 @@ public async Task<SyncSessionControllerStateModel> RefreshState(CancellationToke
         return state;
     }
 
-    public async Task<SyncSessionModel> CreateSyncSession(CreateSyncSessionRequest req, CancellationToken ct = default)
+    public async Task<SyncSessionModel> CreateSyncSession(CreateSyncSessionRequest req, Action<string>? progressCallback = null, CancellationToken ct = default)
     {
         using var _ = await _lock.LockAsync(ct);
         var client = await EnsureDaemon(ct);
 
         await using var prompter = await Prompter.Create(client, true, ct);
+        if (progressCallback != null)
+            prompter.OnProgress += (_, progress) => progressCallback(progress);
+
         var createRes = await client.Synchronization.CreateAsync(new CreateRequest
         {
             Prompter = prompter.Identifier,
@@ -603,6 +606,8 @@ private async Task StopDaemon(CancellationToken ct)
 
     private class Prompter : IAsyncDisposable
     {
+        public event EventHandler<string>? OnProgress;
+
         private readonly AsyncDuplexStreamingCall<HostRequest, HostResponse> _dup;
         private readonly CancellationTokenSource _cts;
         private readonly Task _handleRequestsTask;
@@ -684,6 +689,9 @@ private async Task HandleRequests(CancellationToken ct)
                     if (response.Message == null)
                         throw new InvalidOperationException("Prompting.Host response stream returned a null message");
 
+                    if (!response.IsPrompt)
+                        OnProgress?.Invoke(this, response.Message);
+
                     // Currently we only reply to SSH fingerprint messages with
                     // "yes" and send an empty reply for everything else.
                     var reply = "";
diff --git a/App/ViewModels/FileSyncListViewModel.cs b/App/ViewModels/FileSyncListViewModel.cs
index 7fdd881..d01338c 100644
--- a/App/ViewModels/FileSyncListViewModel.cs
+++ b/App/ViewModels/FileSyncListViewModel.cs
@@ -67,6 +67,9 @@ public partial class FileSyncListViewModel : ObservableObject
     public partial string NewSessionRemotePath { get; set; } = "";
     // TODO: NewSessionRemotePathDialogOpen for remote path
 
+    [ObservableProperty]
+    public partial string NewSessionStatus { get; set; } = "";
+
     public bool NewSessionCreateEnabled
     {
         get
@@ -187,6 +190,7 @@ private void ClearNewForm()
         NewSessionLocalPath = "";
         NewSessionRemoteHost = "";
         NewSessionRemotePath = "";
+        NewSessionStatus = "";
     }
 
     [RelayCommand]
@@ -263,13 +267,26 @@ private void CancelNewSession()
         ClearNewForm();
     }
 
+    private void OnCreateSessionProgress(string message)
+    {
+        // Ensure we're on the UI thread.
+        if (_dispatcherQueue == null) return;
+        if (!_dispatcherQueue.HasThreadAccess)
+        {
+            _dispatcherQueue.TryEnqueue(() => OnCreateSessionProgress(message));
+            return;
+        }
+
+        NewSessionStatus = message;
+    }
+
     [RelayCommand]
     private async Task ConfirmNewSession()
     {
         if (OperationInProgress || !NewSessionCreateEnabled) return;
         OperationInProgress = true;
 
-        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
+        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
         try
         {
             // The controller will send us a state changed event.
@@ -286,7 +303,7 @@ await _syncSessionController.CreateSyncSession(new CreateSyncSessionRequest
                     Host = NewSessionRemoteHost,
                     Path = NewSessionRemotePath,
                 },
-            }, cts.Token);
+            }, OnCreateSessionProgress, cts.Token);
 
             ClearNewForm();
         }
@@ -304,6 +321,7 @@ await _syncSessionController.CreateSyncSession(new CreateSyncSessionRequest
         finally
         {
             OperationInProgress = false;
+            NewSessionStatus = "";
         }
     }
 
diff --git a/App/Views/Pages/FileSyncListMainPage.xaml b/App/Views/Pages/FileSyncListMainPage.xaml
index d38bc29..5a96898 100644
--- a/App/Views/Pages/FileSyncListMainPage.xaml
+++ b/App/Views/Pages/FileSyncListMainPage.xaml
@@ -274,8 +274,11 @@
                             <ColumnDefinition Width="2*" MinWidth="200" />
                             <ColumnDefinition Width="1*" MinWidth="120" />
                             <ColumnDefinition Width="2*" MinWidth="200" />
-                            <ColumnDefinition Width="1*" MinWidth="100" MaxWidth="200" />
-                            <ColumnDefinition Width="1*" MinWidth="100" MaxWidth="200" />
+                            <!--
+                                To fit the status better, the last two columns
+                                are merged for the new sync row.
+                            -->
+                            <ColumnDefinition Width="2*" MinWidth="200" MaxWidth="400" />
                         </Grid.ColumnDefinitions>
 
                         <Border Grid.Column="0" Padding="0">
@@ -340,6 +343,13 @@
                                 HorizontalAlignment="Stretch"
                                 Text="{x:Bind ViewModel.NewSessionRemotePath, Mode=TwoWay}" />
                         </Border>
+                        <Border Grid.Column="4">
+                            <TextBlock
+                                Text="{x:Bind ViewModel.NewSessionStatus, Mode=OneWay}"
+                                VerticalAlignment="Center"
+                                TextTrimming="CharacterEllipsis"
+                                IsTextTrimmedChanged="TooltipText_IsTextTrimmedChanged" />
+                        </Border>
                     </Grid>
                 </StackPanel>
             </ScrollView>
diff --git a/Tests.App/Services/MutagenControllerTest.cs b/Tests.App/Services/MutagenControllerTest.cs
index 1605f1c..c834009 100644
--- a/Tests.App/Services/MutagenControllerTest.cs
+++ b/Tests.App/Services/MutagenControllerTest.cs
@@ -112,6 +112,13 @@ public async Task Ok(CancellationToken ct)
         // Ensure the daemon is stopped because all sessions are terminated.
         await AssertDaemonStopped(dataDirectory, ct);
 
+        var progressMessages = new List<string>();
+        void OnProgress(string message)
+        {
+            TestContext.Out.WriteLine("Create session progress: " + message);
+            progressMessages.Add(message);
+        }
+
         var session1 = await controller.CreateSyncSession(new CreateSyncSessionRequest
         {
             Alpha = new CreateSyncSessionRequest.Endpoint
@@ -124,7 +131,10 @@ public async Task Ok(CancellationToken ct)
                 Protocol = CreateSyncSessionRequest.Endpoint.ProtocolKind.Local,
                 Path = betaDirectory.FullName,
             },
-        }, ct);
+        }, OnProgress, ct);
+
+        // There should've been at least one progress message.
+        Assert.That(progressMessages, Is.Not.Empty);
 
         state = controller.GetState();
         Assert.That(state.SyncSessions, Has.Count.EqualTo(1));
@@ -142,7 +152,7 @@ public async Task Ok(CancellationToken ct)
                 Protocol = CreateSyncSessionRequest.Endpoint.ProtocolKind.Local,
                 Path = betaDirectory.FullName,
             },
-        }, ct);
+        }, null, ct);
 
         state = controller.GetState();
         Assert.That(state.SyncSessions, Has.Count.EqualTo(2));
@@ -225,7 +235,7 @@ await controller.CreateSyncSession(new CreateSyncSessionRequest
                     Protocol = CreateSyncSessionRequest.Endpoint.ProtocolKind.Local,
                     Path = betaDirectory.FullName,
                 },
-            }, ct);
+            }, null, ct);
         }
 
         await AssertDaemonStopped(dataDirectory, ct);
@@ -265,7 +275,7 @@ await controller1.CreateSyncSession(new CreateSyncSessionRequest
                     Protocol = CreateSyncSessionRequest.Endpoint.ProtocolKind.Local,
                     Path = betaDirectory.FullName,
                 },
-            }, ct);
+            }, null, ct);
 
             controller2 = new MutagenController(_mutagenBinaryPath, dataDirectory);
             await controller2.RefreshState(ct);