diff --git a/src/java.base/share/classes/jdk/internal/event/SocketConnectEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketConnectEvent.java
new file mode 100644
index 0000000000000..c554349265839
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/event/SocketConnectEvent.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.event;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnixDomainSocketAddress;
+
+/**
+ * A JFR event for when a socket connection is established. This event is mirrored in
+ * {@code jdk.jfr.events.SocketConnectEvent} where the metadata for the event is
+ * provided with annotations.  Some of the methods are replaced by generated
+ * methods when jfr is enabled.  Note that the order of the arguments of the
+ * {@link #commit(long, long, String, String, int)} method must be the same as the
+ * order of the fields.
+ */
+public class SocketConnectEvent extends Event {
+
+    // THE ORDER OF THE FOLLOWING FIELDS IS IMPORTANT!
+    // The order must match the argument order of the generated commit method.
+    public String host;
+    public String address;
+    public int port;
+
+    /**
+     * Actually commit an event.  The implementation is generated automatically.
+     * The order of the fields must be the same as the parameters in this method.
+     * {@code commit(..., String, String, int, long)}
+     *
+     * @param start     timestamp of the start of the operation
+     * @param duration  time in nanoseconds to complete the operation
+     * @param host      remote host of the connection
+     * @param address   remote address of the connection
+     * @param port      remote port of the connection
+     */
+    public static void commit(long start, long duration, String host, String address, int port) {
+        // Generated by JFR
+    }
+
+    /**
+     * Determine if an event should be emitted.  The duration of the operation
+     * must exceed some threshold in order to commit the event.  The implementation
+     * of this method is generated automatically if jfr is enabled.
+     *
+     * @param duration  time in nanoseconds to complete the operation
+     * @return  true if the event should be commited
+     */
+    public static boolean shouldCommit(long duration) {
+        // Generated by JFR
+        return false;
+    }
+
+    /**
+     * Determine if this kind of event is enabled.  The implementation
+     * of this method is generated automatically if jfr is enabled.
+     *
+     * @return true if event is enabled, false otherwise
+     */
+    public static boolean enabled() {
+        // Generated by JFR
+        return false;
+    }
+
+    /**
+     * Fetch the current timestamp in nanoseconds.  This method is used
+     * to determine the start and end of an operation.  The implementation
+     * of this method is generated automatically if jfr is enabled.
+     *
+     * @return  the current timestamp value
+     */
+    public static long timestamp() {
+        // Generated by JFR
+        return 0L;
+    }
+
+    /**
+     * Helper method to offer the data needed to potentially commit an event.
+     * The duration of the operation is computed using the current
+     * timestamp and the given start time.  If the duration is meets
+     * or exceeds the configured value (determined by calling the generated method
+     * {@link #shouldCommit(long)}), an event will be emitted by calling
+     * {@link #commit(long, long, String, String, int)}.
+     *
+     * @param start  the start time
+     * @param remote  the address of the remote socket
+     */
+    public static void offer(long start, SocketAddress remote) {
+        long duration = timestamp() - start;
+        if (shouldCommit(duration)) {
+            if (remote instanceof InetSocketAddress isa) {
+                commit(start, duration, isa.getHostString(), isa.getAddress().getHostAddress(), isa.getPort());
+            } else if (remote instanceof UnixDomainSocketAddress udsa) {
+                String path = "[" + udsa.getPath().toString() + "]";
+                commit(start, duration, "Unix domain socket", path, 0);
+            }
+        }
+    }
+
+    /**
+     * Helper method to offer the data needed to potentially commit an event.
+     * The duration of the operation is computed using the current
+     * timestamp and the given start time.  If the duration is meets
+     * or exceeds the configured value (determined by calling the generated method
+     * {@link #shouldCommit(long)}), an event will be emitted by calling
+     * {@code commit(long, long, String, String, int, long)}
+     *
+     * @param start     timestamp of the start of the operation
+     * @param host      remote host of the connection
+     * @param address   remote address of the connection
+     * @param port      remote port of the connection
+     */
+    public static void offer(long start, String host, InetAddress address, int port) {
+        long duration = timestamp() - start;
+        if (shouldCommit(duration)) {
+            commit(start, duration, host, address.getHostAddress(), port);
+        }
+    }
+}
diff --git a/src/java.base/share/classes/jdk/internal/event/SocketConnectFailedEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketConnectFailedEvent.java
new file mode 100644
index 0000000000000..af9508ab1d502
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/event/SocketConnectFailedEvent.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.event;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnixDomainSocketAddress;
+
+/**
+ * A JFR event for when a socket connection cannot be established. This event is mirrored
+ * in {@code jdk.jfr.events.SocketConnectFailedEvent} where the metadata for the event is
+ * provided with annotations.  Some of the methods are replaced by generated
+ * methods when jfr is enabled.  Note that the order of the arguments of the
+ * {@link #commit(long, long, String, String, int, String)} method must be the same as
+ * the order of the fields.
+ */
+public class SocketConnectFailedEvent extends Event {
+
+    // THE ORDER OF THE FOLLOWING FIELDS IS IMPORTANT!
+    // The order must match the argument order of the generated commit method.
+    public String host;
+    public String address;
+    public int port;
+    public String connectExceptionMessage;
+
+    /**
+     * Actually commit an event.  The implementation is generated automatically.
+     * The order of the fields must be the same as the parameters in this method.
+     * {@code commit(..., String, String, int, long)}
+     *
+     * @param start     timestamp of the start of the operation
+     * @param duration  time in nanoseconds to complete the operation
+     * @param host      remote host of the connection
+     * @param address   remote address of the connection
+     * @param port      remote port of the connection
+     * @param connectEx the connect exception message
+     */
+    public static void commit(long start, long duration, String host, String address, int port, String connectEx) {
+        // Generated by JFR
+    }
+
+    /**
+     * Determine if an event should be emitted.  The duration of the operation
+     * must exceed some threshold in order to commit the event.  The implementation
+     * of this method is generated automatically if jfr is enabled.
+     *
+     * @param duration  time in nanoseconds to complete the operation
+     * @return  true if the event should be commited
+     */
+    public static boolean shouldCommit(long duration) {
+        // Generated by JFR
+        return false;
+    }
+
+    /**
+     * Determine if this kind of event is enabled.  The implementation
+     * of this method is generated automatically if jfr is enabled.
+     *
+     * @return true if event is enabled, false otherwise
+     */
+    public static boolean enabled() {
+        // Generated by JFR
+        return false;
+    }
+
+    /**
+     * Fetch the current timestamp in nanoseconds.  This method is used
+     * to determine the start and end of an operation.  The implementation
+     * of this method is generated automatically if jfr is enabled.
+     *
+     * @return  the current timestamp value
+     */
+    public static long timestamp() {
+        // Generated by JFR
+        return 0L;
+    }
+
+    /**
+     * Helper method to offer the data needed to potentially commit an event.
+     * The duration of the operation is computed using the current
+     * timestamp and the given start time.  If the duration is meets
+     * or exceeds the configured value (determined by calling the generated method
+     * {@link #shouldCommit(long)}), an event will be emitted by calling
+     * {@link #commit(long, long, String, String, int, String)}.
+     *
+     * @param start  the start time
+     * @param remote  the address of the remote socket
+     * @param connectEx the I/O exception thrown
+     */
+    public static void offer(long start, SocketAddress remote, IOException connectEx) {
+        long duration = timestamp() - start;
+        if (shouldCommit(duration)) {
+            String msg = connectEx.toString();
+            if (remote instanceof InetSocketAddress isa) {
+                commit(start, duration, isa.getHostString(), isa.getAddress().getHostAddress(), isa.getPort(), msg);
+            } else if (remote instanceof UnixDomainSocketAddress udsa) {
+                String path = "[" + udsa.getPath().toString() + "]";
+                commit(start, duration, "Unix domain socket", path, 0, msg);
+            }
+        }
+    }
+
+    /**
+     * Helper method to offer the data needed to potentially commit an event.
+     * The duration of the operation is computed using the current
+     * timestamp and the given start time.  If the duration is meets
+     * or exceeds the configured value (determined by calling the generated method
+     * {@link #shouldCommit(long)}), an event will be emitted by calling
+     * {@code commit(long, long, String, String, int, long)}
+     *
+     * @param start     timestamp of the start of the operation
+     * @param host      remote host of the connection
+     * @param address   remote address of the connection
+     * @param port      remote port of the connection
+     * @param connectEx the I/O exception thrown
+     */
+    public static void offer(long start, String host, InetAddress address, int port, IOException connectEx) {
+        long duration = timestamp() - start;
+        if (shouldCommit(duration)) {
+            commit(start, duration, host, address.getHostAddress(), port, connectEx.toString());
+        }
+    }
+}
diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
index 7c64d6721e2c7..71ee6c69d07d5 100644
--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
@@ -53,6 +53,8 @@
 
 import jdk.internal.access.JavaIOFileDescriptorAccess;
 import jdk.internal.access.SharedSecrets;
+import jdk.internal.event.SocketConnectEvent;
+import jdk.internal.event.SocketConnectFailedEvent;
 import jdk.internal.ref.CleanerFactory;
 import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
@@ -563,6 +565,9 @@ protected void connect(SocketAddress remote, int millis) throws IOException {
             address = InetAddress.getLocalHost();
         int port = isa.getPort();
 
+        long connectStart = 0L;
+        IOException connectEx = null;
+
         ReentrantLock connectLock = readLock;
         try {
             connectLock.lock();
@@ -571,6 +576,7 @@ protected void connect(SocketAddress remote, int millis) throws IOException {
                 FileDescriptor fd = beginConnect(address, port);
                 try {
                     configureNonBlockingIfNeeded(fd, millis > 0);
+                    connectStart = SocketConnectEvent.timestamp();
                     int n = Net.connect(fd, address, port);
                     if (n > 0) {
                         // connection established
@@ -600,14 +606,28 @@ protected void connect(SocketAddress remote, int millis) throws IOException {
         } catch (IOException ioe) {
             close();
             if (ioe instanceof SocketTimeoutException) {
-                throw ioe;
+                connectEx = ioe;
             } else if (ioe instanceof InterruptedIOException) {
                 assert Thread.currentThread().isVirtual();
-                throw new SocketException("Closed by interrupt");
+                connectEx = new SocketException("Closed by interrupt");
             } else {
-                throw SocketExceptions.of(ioe, isa);
+                connectEx = SocketExceptions.of(ioe, isa);
+            }
+        }
+
+        // record JFR event
+        if (connectStart != 0L) {
+            String hostname = isa.getHostString();
+            if (connectEx == null && SocketConnectEvent.enabled()) {
+                SocketConnectEvent.offer(connectStart, hostname , address, port);
+            } else if (connectEx != null && SocketConnectFailedEvent.enabled()) {
+                SocketConnectFailedEvent.offer(connectStart, hostname, address, port, connectEx);
             }
         }
+
+        if (connectEx != null) {
+            throw connectEx;
+        }
     }
 
     @Override
diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
index 893bd17ceed89..9d61cceff2e18 100644
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
@@ -59,6 +59,8 @@
 import static java.net.StandardProtocolFamily.INET6;
 import static java.net.StandardProtocolFamily.UNIX;
 
+import jdk.internal.event.SocketConnectEvent;
+import jdk.internal.event.SocketConnectFailedEvent;
 import jdk.internal.event.SocketReadEvent;
 import jdk.internal.event.SocketWriteEvent;
 import sun.net.ConnectionResetException;
@@ -132,6 +134,10 @@ class SocketChannelImpl
     // preserve the semantics of blocking operations.
     private volatile boolean forcedNonBlocking;
 
+    // JFR support, start time of non-blocking connect
+    private long nonBlockingConnectStart;
+
+
     // -- End of fields protected by stateLock
 
     SocketChannelImpl(SelectorProvider sp) throws IOException {
@@ -846,7 +852,7 @@ public boolean isConnectionPending() {
     /**
      * Marks the beginning of a connect operation that might block.
      * @param blocking true if configured blocking
-     * @param isa the remote address
+     * @param sa the remote socket address
      * @throws ClosedChannelException if the channel is closed
      * @throws AlreadyConnectedException if already connected
      * @throws ConnectionPendingException is a connection is pending
@@ -934,6 +940,11 @@ private SocketAddress checkRemote(SocketAddress sa) {
     @Override
     public boolean connect(SocketAddress remote) throws IOException {
         SocketAddress sa = checkRemote(remote);
+
+        boolean connected = false;
+        long connectStart = 0L;
+        IOException connectEx = null;
+
         try {
             readLock.lock();
             try {
@@ -941,10 +952,10 @@ public boolean connect(SocketAddress remote) throws IOException {
                 try {
                     ensureOpen();
                     boolean blocking = isBlocking();
-                    boolean connected = false;
                     try {
                         beginConnect(blocking, sa);
                         configureSocketNonBlockingIfVirtualThread();
+                        connectStart = SocketConnectEvent.timestamp();
                         int n;
                         if (isUnixSocket()) {
                             n = UnixDomainSockets.connect(fd, sa);
@@ -961,11 +972,13 @@ public boolean connect(SocketAddress remote) throws IOException {
                                 polled = Net.pollConnectNow(fd);
                             }
                             connected = polled && isOpen();
+                        } else {
+                            // non-blocking and not connected
+                            this.nonBlockingConnectStart = connectStart;
                         }
                     } finally {
                         endConnect(blocking, connected);
                     }
-                    return connected;
                 } finally {
                     writeLock.unlock();
                 }
@@ -975,7 +988,23 @@ public boolean connect(SocketAddress remote) throws IOException {
         } catch (IOException ioe) {
             // connect failed, close the channel
             close();
-            throw SocketExceptions.of(ioe, sa);
+            connectEx = SocketExceptions.of(ioe, sa);
+        }
+
+        // record JFR event
+        if (connectStart != 0L) {
+            if (connected && SocketConnectEvent.enabled()) {
+                SocketConnectEvent.offer(connectStart, sa);
+            } else if (connectEx != null && SocketConnectFailedEvent.enabled()) {
+                SocketConnectFailedEvent.offer(connectStart, sa, connectEx);
+            }
+        }
+
+        if (connectEx == null) {
+            return connected;
+        } else {
+            assert !connected;
+            throw connectEx;
         }
     }
 
@@ -1029,6 +1058,9 @@ private void endFinishConnect(boolean blocking, boolean completed)
 
     @Override
     public boolean finishConnect() throws IOException {
+        long connectStart = 0L;
+        boolean connected = false;
+        IOException connectEx = null;
         try {
             readLock.lock();
             try {
@@ -1037,12 +1069,11 @@ public boolean finishConnect() throws IOException {
                     // no-op if already connected
                     if (isConnected())
                         return true;
-
                     ensureOpen();
                     boolean blocking = isBlocking();
-                    boolean connected = false;
                     try {
                         beginFinishConnect(blocking);
+                        connectStart = this.nonBlockingConnectStart;
                         boolean polled = Net.pollConnectNow(fd);
                         if (blocking) {
                             while (!polled && isOpen()) {
@@ -1055,7 +1086,6 @@ public boolean finishConnect() throws IOException {
                         endFinishConnect(blocking, connected);
                     }
                     assert (blocking && connected) ^ !blocking;
-                    return connected;
                 } finally {
                     writeLock.unlock();
                 }
@@ -1065,7 +1095,23 @@ public boolean finishConnect() throws IOException {
         } catch (IOException ioe) {
             // connect failed, close the channel
             close();
-            throw SocketExceptions.of(ioe, remoteAddress);
+            connectEx = SocketExceptions.of(ioe, remoteAddress);
+        }
+
+        // record JFR event
+        if (connectStart != 0L) {
+            if (connected && SocketConnectEvent.enabled()) {
+                SocketConnectEvent.offer(connectStart, remoteAddress());
+            } else if (connectEx != null && SocketConnectFailedEvent.enabled()) {
+                SocketConnectFailedEvent.offer(connectStart, remoteAddress(), connectEx);
+            }
+        }
+
+        if (connectEx != null) {
+            assert !connected;
+            throw connectEx;
+        } else {
+            return connected;
         }
     }
 
@@ -1289,6 +1335,9 @@ private boolean finishTimedConnect(long nanos) throws IOException {
      */
     void blockingConnect(SocketAddress remote, long nanos) throws IOException {
         SocketAddress sa = checkRemote(remote);
+
+        long connectStart = 0L;
+        IOException connectEx = null;
         try {
             readLock.lock();
             try {
@@ -1302,6 +1351,7 @@ void blockingConnect(SocketAddress remote, long nanos) throws IOException {
                         // change socket to non-blocking
                         lockedConfigureBlocking(false);
                         try {
+                            connectStart = SocketConnectEvent.timestamp();
                             int n;
                             if (isUnixSocket()) {
                                 n = UnixDomainSockets.connect(fd, sa);
@@ -1325,7 +1375,20 @@ void blockingConnect(SocketAddress remote, long nanos) throws IOException {
         } catch (IOException ioe) {
             // connect failed, close the channel
             close();
-            throw SocketExceptions.of(ioe, sa);
+            connectEx = SocketExceptions.of(ioe, sa);
+        }
+
+        // record JFR event
+        if (connectStart != 0L) {
+            if (connectEx == null && SocketConnectEvent.enabled()) {
+                SocketConnectEvent.offer(connectStart, sa);
+            } else if (connectEx != null && SocketConnectFailedEvent.enabled()) {
+                SocketConnectFailedEvent.offer(connectStart, sa, connectEx);
+            }
+        }
+
+        if (connectEx != null) {
+            throw connectEx;
         }
     }
 
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/SocketConnectEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketConnectEvent.java
new file mode 100644
index 0000000000000..d6058d1ececf6
--- /dev/null
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketConnectEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.internal.MirrorEvent;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "SocketConnect")
+@Label("Socket Connect")
+@Category("Java Application")
+@Description("Socket connection established")
+public class SocketConnectEvent extends MirrorEvent {
+
+    @Label("Remote Host")
+    public String host;
+
+    @Label("Remote Address")
+    public String address;
+
+    @Label("Remote Port")
+    public int port;
+}
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/SocketConnectFailedEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketConnectFailedEvent.java
new file mode 100644
index 0000000000000..751e9193b2d7f
--- /dev/null
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketConnectFailedEvent.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.internal.MirrorEvent;
+import jdk.jfr.internal.Type;
+
+@Name(Type.EVENT_NAME_PREFIX + "SocketConnectFailed")
+@Label("Socket Connect Failed")
+@Category("Java Application")
+@Description("Socket connection could not be established")
+public class SocketConnectFailedEvent extends MirrorEvent {
+
+    @Label("Remote Host")
+    public String host;
+
+    @Label("Remote Address")
+    public String address;
+
+    @Label("Remote Port")
+    public int port;
+
+    @Label("Connect Exception Message")
+    public String connectExceptionMessage;
+}
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java
index d0d186e2479d0..85b2f6d9baebd 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java
@@ -62,6 +62,8 @@ public final class JDKEvents {
         jdk.internal.event.SecurityPropertyModificationEvent.class,
         jdk.internal.event.SecurityProviderServiceEvent.class,
         jdk.internal.event.SerializationMisdeclarationEvent.class,
+        jdk.internal.event.SocketConnectEvent.class,
+        jdk.internal.event.SocketConnectFailedEvent.class,
         jdk.internal.event.SocketReadEvent.class,
         jdk.internal.event.SocketWriteEvent.class,
         jdk.internal.event.ThreadSleepEvent.class,
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java
index 48dc0d22cea3a..c3c65cdc91830 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java
@@ -38,6 +38,8 @@
 import jdk.jfr.events.SecurityPropertyModificationEvent;
 import jdk.jfr.events.SecurityProviderServiceEvent;
 import jdk.jfr.events.SerializationMisdeclarationEvent;
+import jdk.jfr.events.SocketConnectEvent;
+import jdk.jfr.events.SocketConnectFailedEvent;
 import jdk.jfr.events.SocketReadEvent;
 import jdk.jfr.events.SocketWriteEvent;
 import jdk.jfr.events.TLSHandshakeEvent;
@@ -65,6 +67,8 @@ final class MirrorEvents {
         register("jdk.internal.event.SecurityPropertyModificationEvent", SecurityPropertyModificationEvent.class);
         register("jdk.internal.event.SecurityProviderServiceEvent", SecurityProviderServiceEvent.class);
         register("jdk.internal.event.SerializationMisdeclarationEvent", SerializationMisdeclarationEvent.class);
+        register("jdk.internal.event.SocketConnectEvent", SocketConnectEvent.class);
+        register("jdk.internal.event.SocketConnectFailedEvent", SocketConnectFailedEvent.class);
         register("jdk.internal.event.SocketReadEvent", SocketReadEvent.class);
         register("jdk.internal.event.SocketWriteEvent", SocketWriteEvent.class);
         register("jdk.internal.event.ThreadSleepEvent", ThreadSleepEvent.class);
diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc
index 57016a9bdd03b..64aaf846dbd6b 100644
--- a/src/jdk.jfr/share/conf/jfr/default.jfc
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc
@@ -738,6 +738,18 @@
       20 ms
     
 
+    
+      true
+      true
+      20 ms
+    
+
+    
+      true
+      true
+      20 ms
+    
+
     
       true
       true
diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc
index 1df3af7475f3e..4befab2994db0 100644
--- a/src/jdk.jfr/share/conf/jfr/profile.jfc
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc
@@ -738,6 +738,18 @@
       10 ms
     
 
+    
+      true
+      true
+      10 ms
+    
+
+    
+      true
+      true
+      10 ms
+    
+
     
       true
       true
diff --git a/test/jdk/jdk/jfr/event/io/IOEvent.java b/test/jdk/jdk/jfr/event/io/IOEvent.java
index a8392e4d35a20..174bb238800e3 100644
--- a/test/jdk/jdk/jfr/event/io/IOEvent.java
+++ b/test/jdk/jdk/jfr/event/io/IOEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -73,13 +73,15 @@ public int hashCode() {
     public static final String EVENT_FILE_FORCE = EventNames.FileForce;
     public static final String EVENT_FILE_READ = EventNames.FileRead;
     public static final String EVENT_FILE_WRITE = EventNames.FileWrite;
+    public static final String EVENT_SOCKET_CONNECT = EventNames.SocketConnect;
+    public static final String EVENT_SOCKET_CONNECT_FAILED = EventNames.SocketConnectFailed;
     public static final String EVENT_SOCKET_READ = EventNames.SocketRead;
     public static final String EVENT_SOCKET_WRITE = EventNames.SocketWrite;
 
-    public enum EventType { UnknownEvent, FileForce, FileRead, FileWrite, SocketRead, SocketWrite }
+    public enum EventType { UnknownEvent, FileForce, FileRead, FileWrite, SocketConnect, SocketConnectFailed, SocketRead, SocketWrite }
 
     private static final String[] eventPaths = {
-        EVENT_UNKNOWN, EVENT_FILE_FORCE, EVENT_FILE_READ, EVENT_FILE_WRITE, EVENT_SOCKET_READ, EVENT_SOCKET_WRITE
+        EVENT_UNKNOWN, EVENT_FILE_FORCE, EVENT_FILE_READ, EVENT_FILE_WRITE, EVENT_SOCKET_CONNECT, EVENT_SOCKET_CONNECT_FAILED, EVENT_SOCKET_READ, EVENT_SOCKET_WRITE
     };
 
     public static boolean isWriteEvent(EventType eventType) {
@@ -94,6 +96,15 @@ public static boolean isFileEvent(EventType eventType) {
         return (eventType == EventType.FileForce || eventType == EventType.FileWrite || eventType == EventType.FileRead);
     }
 
+    public static IOEvent createSocketConnectEvent(Socket s) {
+        return new IOEvent(Thread.currentThread().getName(), EventType.SocketConnect, 0, getAddress(s), false);
+    }
+
+
+    public static IOEvent createSocketConnectFailedEvent(Socket s) {
+        return new IOEvent(Thread.currentThread().getName(), EventType.SocketConnectFailed, 0, getAddress(s), false);
+    }
+
     public static IOEvent createSocketWriteEvent(long size, Socket s) {
         if (size < 0) {
             size = 0;
diff --git a/test/jdk/jdk/jfr/event/io/IOHelper.java b/test/jdk/jdk/jfr/event/io/IOHelper.java
index a8dbe940b03a3..bfa666857b40d 100644
--- a/test/jdk/jdk/jfr/event/io/IOHelper.java
+++ b/test/jdk/jdk/jfr/event/io/IOHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,14 +26,20 @@
 import static jdk.test.lib.Asserts.assertEquals;
 import static jdk.test.lib.Asserts.assertTrue;
 
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import jdk.jfr.Recording;
 import jdk.jfr.event.io.IOEvent.EventType;
 
 import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
 import jdk.test.lib.jfr.Events;
 
 
@@ -130,4 +136,56 @@ private static void logEvents(List actualEvents, List expected
         }
     }
 
+    public interface ConnectExceptionMaker {
+        /**
+         * Implementation should attempt to connect to the given address, which
+         * should cause an exception to be generated.
+         * @return the exception generated, or null if the connection was
+         *         unexpectedly successful.
+         * @throws Throwable if something else failed
+         */
+        IOException generateConnectException(SocketAddress addr) throws Throwable;
+    }
+
+    /**
+     * Attempt to test JFR events for an exception condition while attempting to connect
+     * a socket.  The given function attempts to make the connection which we would like to
+     * fail so we can inspect the associated JFR event.  To do this a range of IANA reserved
+     * ports are used which it is expected will be unused.
+     *
+     * @param func   an implementation of a connection attempt
+     * @throws Throwable
+     */
+    public static void testConnectException(ConnectExceptionMaker func) throws Throwable {
+        InetAddress lb = InetAddress.getLoopbackAddress();
+        boolean completed = false;
+        for (int port = 225; (completed == false)  && (port <= 241); ++port) {
+            completed = testConnectExceptionOnPort(new InetSocketAddress(lb, port), func);
+        }
+        if (! completed)
+            throw new Exception("Unable to setup connect exception");
+    }
+
+    private static boolean testConnectExceptionOnPort(SocketAddress addr, ConnectExceptionMaker func) throws Throwable {
+        try (Recording recording = new Recording()) {
+            recording.enable(IOEvent.EVENT_SOCKET_CONNECT_FAILED);
+            recording.start();
+
+            // try to connect to a port we expect to be unused
+            // to generate an exception
+            IOException connectException = func.generateConnectException(addr);
+            if (connectException == null)
+                return false;
+
+            recording.stop();
+            List events = Events.fromRecording(recording);
+            Asserts.assertEquals(1, events.size());
+            RecordedEvent event = events.get(0);
+            Asserts.assertEquals(IOEvent.EVENT_SOCKET_CONNECT_FAILED, event.getEventType().getName());
+            Asserts.assertNotNull(connectException);
+            String eventMessage = event.getString("connectExceptionMessage");
+            Asserts.assertEquals(eventMessage, connectException.toString());
+            return true;
+        }
+    }
 }
diff --git a/test/jdk/jdk/jfr/event/io/TestSocketAdapterEvents.java b/test/jdk/jdk/jfr/event/io/TestSocketAdapterEvents.java
index 9ac57b839fb2c..7eef7734444dd 100644
--- a/test/jdk/jdk/jfr/event/io/TestSocketAdapterEvents.java
+++ b/test/jdk/jdk/jfr/event/io/TestSocketAdapterEvents.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,10 +31,9 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
-import java.nio.ByteBuffer;
+import java.net.SocketAddress;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
-import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -65,13 +64,15 @@ private synchronized void addExpectedEvent(IOEvent event) {
 
     public static void main(String[] args) throws Throwable {
         new TestSocketAdapterEvents().test();
+        IOHelper.testConnectException(TestSocketAdapterEvents::makeConnectException);
     }
 
-    public void test() throws Throwable {
+    private void test() throws Throwable {
         try (Recording recording = new Recording()) {
             try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
-                recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0));
-                recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0));
+                recording.enable(IOEvent.EVENT_SOCKET_CONNECT);
+                recording.enable(IOEvent.EVENT_SOCKET_READ);
+                recording.enable(IOEvent.EVENT_SOCKET_WRITE);
                 recording.start();
 
                 InetAddress lb = InetAddress.getLoopbackAddress();
@@ -85,36 +86,38 @@ public void xrun() throws IOException {
                              InputStream is = s.getInputStream()) {
 
                             int readInt = is.read();
-                            assertEquals(readInt, writeInt, "Wrong readInt");
+                            assertEquals(writeInt, readInt, "Wrong readInt");
                             addExpectedEvent(IOEvent.createSocketReadEvent(1, s));
 
                             int bytesRead = is.read(bs, 0, 3);
-                            assertEquals(bytesRead, 3, "Wrong bytesRead partial buffer");
+                            assertEquals(3, bytesRead, "Wrong bytesRead partial buffer");
                             addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s));
 
                             bytesRead = is.read(bs);
-                            assertEquals(bytesRead, writeBuf.length, "Wrong bytesRead full buffer");
+                            assertEquals(writeBuf.length, bytesRead, "Wrong bytesRead full buffer");
                             addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s));
 
                             // Try to read more, but writer have closed. Should
                             // get EOF.
                             readInt = is.read();
-                            assertEquals(readInt, -1, "Wrong readInt at EOF");
+                            assertEquals(-1, readInt, "Wrong readInt at EOF");
                             addExpectedEvent(IOEvent.createSocketReadEvent(-1, s));
                         }
                     }
                 });
                 readerThread.start();
 
-                try (SocketChannel sc = SocketChannel.open(ssc.getLocalAddress());
-                     Socket s = sc.socket(); OutputStream os = s.getOutputStream()) {
-
-                    os.write(writeInt);
-                    addExpectedEvent(IOEvent.createSocketWriteEvent(1, s));
-                    os.write(writeBuf, 0, 3);
-                    addExpectedEvent(IOEvent.createSocketWriteEvent(3, s));
-                    os.write(writeBuf);
-                    addExpectedEvent(IOEvent.createSocketWriteEvent(writeBuf.length, s));
+                try (SocketChannel sc = SocketChannel.open(); Socket s = sc.socket()) {
+                    s.connect(ssc.getLocalAddress());
+                    addExpectedEvent(IOEvent.createSocketConnectEvent(s));
+                    try (OutputStream os = s.getOutputStream()) {
+                        os.write(writeInt);
+                        addExpectedEvent(IOEvent.createSocketWriteEvent(1, s));
+                        os.write(writeBuf, 0, 3);
+                        addExpectedEvent(IOEvent.createSocketWriteEvent(3, s));
+                        os.write(writeBuf);
+                        addExpectedEvent(IOEvent.createSocketWriteEvent(writeBuf.length, s));
+                    }
                 }
 
                 readerThread.joinAndThrow();
@@ -124,4 +127,15 @@ public void xrun() throws IOException {
             }
         }
     }
+
+    private static IOException makeConnectException(SocketAddress addr) throws Throwable {
+        IOException connectException = null;
+        try (SocketChannel sc = SocketChannel.open()) {
+            Socket s = sc.socket();
+            s.connect(addr);
+        } catch (IOException ioe) {
+            connectException = ioe;
+        }
+        return connectException;
+    }
 }
diff --git a/test/jdk/jdk/jfr/event/io/TestSocketChannelEvents.java b/test/jdk/jdk/jfr/event/io/TestSocketChannelEvents.java
index fc045e55caa6e..9455487d404c8 100644
--- a/test/jdk/jdk/jfr/event/io/TestSocketChannelEvents.java
+++ b/test/jdk/jdk/jfr/event/io/TestSocketChannelEvents.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,10 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
-import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -61,13 +61,17 @@ private synchronized void addExpectedEvent(IOEvent event) {
 
     public static void main(String[] args) throws Throwable {
         new TestSocketChannelEvents().test();
+        new TestSocketChannelEvents().testNonBlockingConnect();
+        IOHelper.testConnectException(TestSocketChannelEvents::makeBlockingConnectException);
+        IOHelper.testConnectException(TestSocketChannelEvents::makeNonBlockingConnectException);
     }
 
-    public void test() throws Throwable {
+    private void test() throws Throwable {
         try (Recording recording = new Recording()) {
             try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
-                recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0));
-                recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0));
+                recording.enable(IOEvent.EVENT_SOCKET_CONNECT);
+                recording.enable(IOEvent.EVENT_SOCKET_READ);
+                recording.enable(IOEvent.EVENT_SOCKET_WRITE);
                 recording.start();
 
                 InetAddress lb = InetAddress.getLoopbackAddress();
@@ -80,13 +84,13 @@ public void xrun() throws IOException {
                         ByteBuffer bufB = ByteBuffer.allocate(bufSizeB);
                         try (SocketChannel sc = ssc.accept()) {
                             int readSize = sc.read(bufA);
-                            assertEquals(readSize, bufSizeA, "Wrong readSize bufA");
+                            assertEquals(bufSizeA, readSize, "Wrong readSize bufA");
                             addExpectedEvent(IOEvent.createSocketReadEvent(bufSizeA, sc.socket()));
 
                             bufA.clear();
                             bufA.limit(1);
                             readSize = (int) sc.read(new ByteBuffer[] { bufA, bufB });
-                            assertEquals(readSize, 1 + bufSizeB, "Wrong readSize 1+bufB");
+                            assertEquals(1 + bufSizeB, readSize, "Wrong readSize 1+bufB");
                             addExpectedEvent(IOEvent.createSocketReadEvent(readSize, sc.socket()));
 
                             // We try to read, but client have closed. Should
@@ -94,7 +98,7 @@ public void xrun() throws IOException {
                             bufA.clear();
                             bufA.limit(1);
                             readSize = sc.read(bufA);
-                            assertEquals(readSize, -1, "Wrong readSize at EOF");
+                            assertEquals(-1, readSize, "Wrong readSize at EOF");
                             addExpectedEvent(IOEvent.createSocketReadEvent(-1, sc.socket()));
                         }
                     }
@@ -102,6 +106,7 @@ public void xrun() throws IOException {
                 readerThread.start();
 
                 try (SocketChannel sc = SocketChannel.open(ssc.getLocalAddress())) {
+                    addExpectedEvent(IOEvent.createSocketConnectEvent(sc.socket()));
                     ByteBuffer bufA = ByteBuffer.allocateDirect(bufSizeA);
                     ByteBuffer bufB = ByteBuffer.allocateDirect(bufSizeB);
                     for (int i = 0; i < bufSizeA; ++i) {
@@ -119,7 +124,7 @@ public void xrun() throws IOException {
                     bufA.clear();
                     bufA.limit(1);
                     int bytesWritten = (int) sc.write(new ByteBuffer[] { bufA, bufB });
-                    assertEquals(bytesWritten, 1 + bufSizeB, "Wrong bytesWritten 1+bufB");
+                    assertEquals(1 + bufSizeB, bytesWritten, "Wrong bytesWritten 1+bufB");
                     addExpectedEvent(IOEvent.createSocketWriteEvent(bytesWritten, sc.socket()));
                 }
 
@@ -130,4 +135,58 @@ public void xrun() throws IOException {
             }
         }
     }
+
+    private void testNonBlockingConnect() throws Throwable {
+        try (Recording recording = new Recording()) {
+            try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
+                recording.enable(IOEvent.EVENT_SOCKET_CONNECT);
+                recording.start();
+
+                InetAddress lb = InetAddress.getLoopbackAddress();
+                ssc.bind(new InetSocketAddress(lb, 0));
+                SocketAddress addr = ssc.getLocalAddress();
+
+                try (SocketChannel sc = SocketChannel.open()) {
+                    sc.configureBlocking(false);
+                    sc.connect(addr);
+                    try (SocketChannel serverSide = ssc.accept()) {
+                        while (! sc.finishConnect()) {
+                            Thread.sleep(1);
+                        }
+                    }
+                    addExpectedEvent(IOEvent.createSocketConnectEvent(sc.socket()));
+                }
+
+                recording.stop();
+                List events = Events.fromRecording(recording);
+                IOHelper.verifyEquals(events, expectedEvents);
+            }
+        }
+    }
+
+    private static IOException makeBlockingConnectException(SocketAddress addr) throws Throwable {
+        IOException connectException = null;
+        try (SocketChannel sc = SocketChannel.open(addr)) {
+        } catch (IOException ioe) {
+            connectException = ioe;
+        }
+        return connectException;
+    }
+
+    private static IOException makeNonBlockingConnectException(SocketAddress addr) throws Throwable {
+        IOException connectException = null;
+        try (SocketChannel sc = SocketChannel.open()) {
+            sc.configureBlocking(false);
+            try {
+                boolean connected = sc.connect(addr);
+                while (!connected) {
+                    Thread.sleep(10);
+                    connected = sc.finishConnect();
+                }
+            } catch (IOException ioe) {
+                connectException = ioe;
+            }
+        }
+        return connectException;
+    }
 }
diff --git a/test/jdk/jdk/jfr/event/io/TestSocketEvents.java b/test/jdk/jdk/jfr/event/io/TestSocketEvents.java
index d73c5010cf7d0..3bbe8b6cd8164 100644
--- a/test/jdk/jdk/jfr/event/io/TestSocketEvents.java
+++ b/test/jdk/jdk/jfr/event/io/TestSocketEvents.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
-import java.time.Duration;
+import java.net.SocketAddress;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -63,13 +63,15 @@ private synchronized void addExpectedEvent(IOEvent event) {
 
     public static void main(String[] args) throws Throwable {
         new TestSocketEvents().test();
+        IOHelper.testConnectException(TestSocketEvents::makeConnectException);
     }
 
     private void test() throws Throwable {
         try (Recording recording = new Recording()) {
             try (ServerSocket ss = new ServerSocket()) {
-                recording.enable(IOEvent.EVENT_SOCKET_READ).withThreshold(Duration.ofMillis(0));
-                recording.enable(IOEvent.EVENT_SOCKET_WRITE).withThreshold(Duration.ofMillis(0));
+                recording.enable(IOEvent.EVENT_SOCKET_CONNECT);
+                recording.enable(IOEvent.EVENT_SOCKET_READ);
+                recording.enable(IOEvent.EVENT_SOCKET_WRITE);
                 recording.start();
 
                 InetAddress lb = InetAddress.getLoopbackAddress();
@@ -81,21 +83,21 @@ public void xrun() throws IOException {
                         byte[] bs = new byte[4];
                         try (Socket s = ss.accept(); InputStream is = s.getInputStream()) {
                             int readInt = is.read();
-                            assertEquals(readInt, writeInt, "Wrong readInt");
+                            assertEquals(writeInt, readInt, "Wrong readInt");
                             addExpectedEvent(IOEvent.createSocketReadEvent(1, s));
 
                             int bytesRead = is.read(bs, 0, 3);
-                            assertEquals(bytesRead, 3, "Wrong bytesRead partial buffer");
+                            assertEquals(3, bytesRead, "Wrong bytesRead partial buffer");
                             addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s));
 
                             bytesRead = is.read(bs);
-                            assertEquals(bytesRead, writeBuf.length, "Wrong bytesRead full buffer");
+                            assertEquals(writeBuf.length, bytesRead, "Wrong bytesRead full buffer");
                             addExpectedEvent(IOEvent.createSocketReadEvent(bytesRead, s));
 
                             // Try to read more, but writer have closed. Should
                             // get EOF.
                             readInt = is.read();
-                            assertEquals(readInt, -1, "Wrong readInt at EOF");
+                            assertEquals(-1, readInt, "Wrong readInt at EOF");
                             addExpectedEvent(IOEvent.createSocketReadEvent(-1, s));
                         }
                     }
@@ -104,6 +106,7 @@ public void xrun() throws IOException {
 
                 try (Socket s = new Socket()) {
                     s.connect(ss.getLocalSocketAddress());
+                    addExpectedEvent(IOEvent.createSocketConnectEvent(s));
                     try (OutputStream os = s.getOutputStream()) {
                         os.write(writeInt);
                         addExpectedEvent(IOEvent.createSocketWriteEvent(1, s));
@@ -121,4 +124,14 @@ public void xrun() throws IOException {
             }
         }
     }
+
+    private static IOException makeConnectException(SocketAddress addr) throws Throwable {
+        IOException connectException = null;
+        try (Socket s = new Socket()) {
+            s.connect(addr);
+        } catch (IOException ioe) {
+            connectException = ioe;
+        }
+        return connectException;
+    }
 }
diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java
index 77fe554c9baaa..f7df4c5ee1ba7 100644
--- a/test/lib/jdk/test/lib/jfr/EventNames.java
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java
@@ -194,6 +194,8 @@ public class EventNames {
     public static final String FileForce  = PREFIX + "FileForce";
     public static final String FileRead = PREFIX + "FileRead";
     public static final String FileWrite = PREFIX + "FileWrite";
+    public static final String SocketConnect = PREFIX + "SocketConnect";
+    public static final String SocketConnectFailed = PREFIX + "SocketConnectFailed";
     public static final String SocketRead = PREFIX + "SocketRead";
     public static final String SocketWrite = PREFIX + "SocketWrite";
     public static final String ExceptionStatistics = PREFIX + "ExceptionStatistics";