<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r" -->

---
title: Chasing missing SIGINT signals - SSH | daily.dev
description: A bug report showed Teleport's tsh SSH client ignoring Ctrl-C (SIGINT) when tailing logs across multiple servers, printing ^C but continuing to block. The root...
canonical: https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Chasing missing SIGINT signals - SSH | daily.dev
og:description: A bug report showed Teleport's tsh SSH client ignoring Ctrl-C (SIGINT) when tailing logs across multiple servers, printing ^C but continuing to block. The root...
og:url: https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r
og:image: https://api.daily.dev/og/posts/hmlV9W50r.png
og:image:alt: Chasing missing SIGINT signals - SSH
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Chasing missing SIGINT signals - SSH

**[Teleport](https://daily.dev/sources/teleport)** · 4 min read · 0 upvotes · 0 comments

## Summary

A bug report showed Teleport's tsh SSH client ignoring Ctrl-C (SIGINT) when tailing logs across multiple servers, printing ^C but continuing to block. The root cause traces to SSH protocol internals: whether a PTY is allocated determines where signal handling happens - shell requests use raw-mode PTYs that forward everything to the remote, while exec requests rely on the local PTY sending SIGINT to the foreground process. Because Teleport's Go SSH library lacks SSH_MSG_DISCONNECT support and Teleport spawns processes differently than OpenSSH, tsh wasn't properly killing the remote process on SIGINT. The fix propagates SIGINT to the running remote command, kills it, and closes the connection.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://goteleport.com/blog/ssh-client-signal-handling>

## Questions this post answers

### Why does Ctrl-C not stop a command when using ssh with a remote exec request like tail -f?

With exec requests, no pseudo terminal is typically allocated on the remote side, so Ctrl-C is handled locally: the client's PTY sends SIGINT to the foreground SSH client process, which must then explicitly tell the server to terminate the session. If the client mishandles this signal, the remote command keeps running and the terminal appears to hang after printing ^C.

_Debugging terminal signal quirks in ssh tooling gets easier with technical deep dives like this on daily.dev._

### What is the difference in how SSH handles SIGINT for shell requests versus exec requests?

Shell requests allocate a pseudo terminal (PTY) on the remote machine and put the local PTY in raw mode, so Ctrl-C is sent straight to the remote PTY, which converts it into a SIGINT for the foreground process there. Exec requests, used for one-off commands like tail -f, typically skip PTY allocation, so the local PTY intercepts Ctrl-C and sends SIGINT to the local client process instead.

_Engineers untangling SSH protocol behavior can find deep technical writeups like this via daily.dev._

### Why couldn't Teleport's tsh client send an SSH_MSG_DISCONNECT like OpenSSH does when terminating a session?

The Go SSH library used by Teleport did not support sending SSH_MSG_DISCONNECT messages, and even if it had, Teleport's process spawning model differs from OpenSSH's, complicating how to kill the child process. Instead, tsh closes the channel and client, then Teleport reaps the connection's resources and sends SIGKILL to any remaining processes.

_Developers working around Go SSH library limitations can track real-world fixes like this on daily.dev._

## Similar posts on daily.dev

- [tail CI logs over SSH](https://daily.dev/posts/tail-ci-logs-over-ssh-wd0o279pz) · Lobsters · 2 upvotes · 0 comments
- [Ctrl-C in psql gives me the heebie-jeebies](https://daily.dev/posts/ctrl-c-in-psql-gives-me-the-heebie-jeebies-yovccjvap) · Neon · 0 upvotes · 0 comments
- [ptr.pet/tobi](https://daily.dev/posts/ptr-pet-tobi-bzakrwlzd) · Awesome Go · 2 upvotes · 0 comments
- [Can the Erlang shell support Ctrl\+D by default?](https://daily.dev/posts/can-the-erlang-shell-support-ctrl-d-by-default--kirasba5j) · Erlang Forums · 0 upvotes · 0 comments

---

Tags: [#golang](https://daily.dev/tags/golang), [#ssh](https://daily.dev/tags/ssh)

[View this post on daily.dev](https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Chasing missing SIGINT signals - SSH","url":"https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r"},"datePublished":"2026-08-23T12:22:06.725Z","dateModified":"2026-08-23T12:43:47.674Z","description":"A bug report showed Teleport's tsh SSH client ignoring Ctrl-C (SIGINT) when tailing logs across multiple servers, printing ^C but continuing to block. The root...","image":"https://media.daily.dev/image/upload/s--1KxV4ohY--/f_auto/v1722860400/public/Placeholder%2007","thumbnailUrl":"https://media.daily.dev/image/upload/s--1KxV4ohY--/f_auto/v1722860400/public/Placeholder%2007","isAccessibleForFree":true,"articleSection":"Teleport","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Teleport","logo":"https://media.daily.dev/image/upload/s--Dw-Bbw6O--/c_limit,w_256/f_auto,q_auto/v1787487494/logos/teleport?_a=BAMAMicg0","url":"https://daily.dev/sources/teleport"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"golang,ssh","timeRequired":"PT4M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Teleport","item":"https://daily.dev/sources/teleport"},{"@type":"ListItem","position":3,"name":"Chasing missing SIGINT signals - SSH"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/chasing-missing-sigint-signals---ssh-hmlv9w50r#faq","mainEntity":[{"@type":"Question","name":"Why does Ctrl-C not stop a command when using ssh with a remote exec request like tail -f?","acceptedAnswer":{"@type":"Answer","text":"With exec requests, no pseudo terminal is typically allocated on the remote side, so Ctrl-C is handled locally: the client's PTY sends SIGINT to the foreground SSH client process, which must then explicitly tell the server to terminate the session. If the client mishandles this signal, the remote command keeps running and the terminal appears to hang after printing ^C. Debugging terminal signal quirks in ssh tooling gets easier with technical deep dives like this on daily.dev."}},{"@type":"Question","name":"What is the difference in how SSH handles SIGINT for shell requests versus exec requests?","acceptedAnswer":{"@type":"Answer","text":"Shell requests allocate a pseudo terminal (PTY) on the remote machine and put the local PTY in raw mode, so Ctrl-C is sent straight to the remote PTY, which converts it into a SIGINT for the foreground process there. Exec requests, used for one-off commands like tail -f, typically skip PTY allocation, so the local PTY intercepts Ctrl-C and sends SIGINT to the local client process instead. Engineers untangling SSH protocol behavior can find deep technical writeups like this via daily.dev."}},{"@type":"Question","name":"Why couldn't Teleport's tsh client send an SSH_MSG_DISCONNECT like OpenSSH does when terminating a session?","acceptedAnswer":{"@type":"Answer","text":"The Go SSH library used by Teleport did not support sending SSH_MSG_DISCONNECT messages, and even if it had, Teleport's process spawning model differs from OpenSSH's, complicating how to kill the child process. Instead, tsh closes the channel and client, then Teleport reaps the connection's resources and sends SIGKILL to any remaining processes. Developers working around Go SSH library limitations can track real-world fixes like this on daily.dev."}}]}
```

